Version update

Version update
This commit is contained in:
Theo Arends 2018-08-28 16:33:05 +02:00
parent 624ee28db3
commit 06604b7f09
10 changed files with 1 additions and 5193 deletions

View File

@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_ #ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_
#define VERSION 0x0601010D #define VERSION 0x06020000
#define D_PROGRAMNAME "Sonoff-Tasmota" #define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends" #define D_AUTHOR "Theo Arends"

File diff suppressed because it is too large Load Diff

View File

@ -1,402 +0,0 @@
/*
xdrv_99_debug.ino - debug support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
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/>.
*/
//#define USE_DEBUG_DRIVER
#ifdef DEBUG_THEO
#ifndef USE_DEBUG_DRIVER
#define USE_DEBUG_DRIVER
#endif // USE_DEBUG_DRIVER
#endif // DEBUG_THEO
#ifdef USE_DEBUG_DRIVER
#ifndef CPU_LOAD_CHECK
#define CPU_LOAD_CHECK 1 // Seconds between each CPU_LOAD log
#endif
/*********************************************************************************************\
* Debug commands
\*********************************************************************************************/
#define D_CMND_CFGDUMP "CfgDump"
#define D_CMND_CFGPOKE "CfgPoke"
#define D_CMND_CFGPEEK "CfgPeek"
#define D_CMND_CFGXOR "CfgXor"
#define D_CMND_EXCEPTION "Exception"
#define D_CMND_CPUCHECK "CpuChk"
enum DebugCommands { CMND_CFGDUMP, CMND_CFGPEEK, CMND_CFGPOKE, CMND_CFGXOR, CMND_EXCEPTION, CMND_CPUCHECK };
const char kDebugCommands[] PROGMEM = D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" D_CMND_CFGXOR "|" D_CMND_EXCEPTION "|" D_CMND_CPUCHECK;
uint32_t CPU_loops = 0;
uint32_t CPU_last_millis = 0;
uint32_t CPU_last_loop_time = 0;
uint8_t CPU_load_check = CPU_LOAD_CHECK;
/*******************************************************************************************/
#ifdef DEBUG_THEO
void ExceptionTest(byte type)
{
/*
Exception (28):
epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000007 depc=0x00000000
ctx: cont
sp: 3fff1f30 end: 3fff2840 offset: 01a0
>>>stack>>>
3fff20d0: 202c3573 756f7247 2c302070 646e4920
3fff20e0: 40236a6e 7954202c 45206570 00454358
3fff20f0: 00000010 00000007 00000000 3fff2180
3fff2100: 3fff2190 40107bfc 3fff3e4c 3fff22c0
3fff2110: 40261934 000000f0 3fff22c0 401004d8
3fff2120: 40238fcf 00000050 3fff2100 4021fc10
3fff2130: 3fff32bc 4021680c 3ffeade1 4021ff7d
3fff2140: 3fff2190 3fff2180 0000000c 7fffffff
3fff2150: 00000019 00000000 00000000 3fff21c0
3fff2160: 3fff23f3 3ffe8e08 00000000 4021ffb4
3fff2170: 3fff2190 3fff2180 0000000c 40201118
3fff2180: 3fff21c0 0000003c 3ffef840 00000007
3fff2190: 00000000 00000000 00000000 40201128
3fff21a0: 3fff23f3 000000f1 3fff23ec 4020fafb
3fff21b0: 3fff23f3 3fff21c0 3fff21d0 3fff23f6
3fff21c0: 00000000 3fff23fb 4022321b 00000000
Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
Decoding 14 results
0x40236a6e: ets_vsnprintf at ?? line ?
0x40107bfc: vsnprintf at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/libc_replacements.c line 387
0x40261934: bignum_exptmod at ?? line ?
0x401004d8: malloc at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1664
0x40238fcf: wifi_station_get_connect_status at ?? line ?
0x4021fc10: operator new[](unsigned int) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/abi.cpp line 57
0x4021680c: ESP8266WiFiSTAClass::status() at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src/ESP8266WiFiSTA.cpp line 569
0x4021ff7d: vsnprintf_P(char*, unsigned int, char const*, __va_list_tag) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
0x4021ffb4: snprintf_P(char*, unsigned int, char const*, ...) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
0x40201118: atol at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
0x40201128: atoi at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
0x4020fafb: MqttDataHandler(char*, unsigned char*, unsigned int) at R:\Arduino\Work-ESP8266\Theo\sonoff\sonoff-4\sonoff/sonoff.ino line 679 (discriminator 1)
0x4022321b: pp_attach at ?? line ?
00:00:08 MQTT: tele/sonoff/INFO3 = {"Started":"Fatal exception:28 flag:2 (EXCEPTION) epc1:0x4000bf64 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000007 depc:0x00000000"}
*/
if (1 == type) {
char svalue[10];
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); // Exception 28 as number in string (7 in excvaddr)
}
/*
14:50:52 osWatch: FreeRam 25896, rssi 68, last_run 0
14:51:02 osWatch: FreeRam 25896, rssi 58, last_run 0
14:51:03 CMND: exception 2
14:51:12 osWatch: FreeRam 25360, rssi 60, last_run 8771
14:51:22 osWatch: FreeRam 25360, rssi 62, last_run 18771
14:51:32 osWatch: FreeRam 25360, rssi 62, last_run 28771
14:51:42 osWatch: FreeRam 25360, rssi 62, last_run 38771
14:51:42 osWatch: Warning, loop blocked. Restart now
*/
if (2 == type) {
while(1) delay(1000); // this will trigger the os watch
}
}
/*******************************************************************************************/
void RtcSettingsDump()
{
#define CFG_COLS 16
uint16_t idx;
uint16_t maxrow;
uint16_t row;
uint16_t col;
uint8_t *buffer = (uint8_t *) &RtcSettings;
maxrow = ((sizeof(RTCMEM)+CFG_COLS)/CFG_COLS);
for (row = 0; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (col = 0; col < CFG_COLS; col++) {
// if (!(col%4)) {
// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
// }
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data);
AddLog(LOG_LEVEL_INFO);
}
}
#endif // DEBUG_THEO
/*******************************************************************************************/
void CpuLoadLoop()
{
CPU_last_loop_time = millis();
if (CPU_load_check && CPU_last_millis) {
CPU_loops ++;
if ((CPU_last_millis + (CPU_load_check *1000)) <= CPU_last_loop_time) {
#if defined(F_CPU) && (F_CPU == 160000000L)
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *800) );
CPU_loops = CPU_loops / CPU_load_check;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(160MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#else
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *400) );
CPU_loops = CPU_loops / CPU_load_check;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(80MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#endif
AddLog(LOG_LEVEL_DEBUG);
CPU_last_millis = CPU_last_loop_time;
CPU_loops = 0;
}
}
}
/*******************************************************************************************/
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1)
// All version before core 2.4.2
extern "C" {
#include <cont.h>
extern cont_t g_cont;
}
void DebugFreeMem()
{
// https://github.com/esp8266/Arduino/issues/2557
register uint32_t *sp asm("a1");
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d, UnmodifiedStack %d (%s)"),
// ESP.getFreeHeap(), 4 * (sp - g_cont.stack), cont_get_free_stack(&g_cont), XdrvMailbox.data);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"),
ESP.getFreeHeap(), 4 * (sp - g_cont.stack), XdrvMailbox.data);
AddLog(LOG_LEVEL_DEBUG);
}
#else
// All version from core 2.4.2
// https://github.com/esp8266/Arduino/pull/5018
// https://github.com/esp8266/Arduino/pull/4553
extern "C" {
#include <cont.h>
extern cont_t* g_pcont;
}
void DebugFreeMem()
{
// https://github.com/esp8266/Arduino/issues/2557
register uint32_t *sp asm("a1");
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"),
ESP.getFreeHeap(), 4 * (sp - g_pcont->stack), XdrvMailbox.data);
AddLog(LOG_LEVEL_DEBUG);
}
#endif // ARDUINO_ESP8266_RELEASE_2_x_x
/*******************************************************************************************/
void DebugCfgDump(char* parms)
{
#define CFG_COLS 16
uint16_t idx;
uint16_t maxrow;
uint16_t row;
uint16_t col;
char *p;
uint8_t *buffer = (uint8_t *) &Settings;
maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS);
uint16_t srow = strtol(parms, &p, 16) / CFG_COLS;
uint16_t mrow = strtol(p, &p, 10);
// snprintf_P(log_data, sizeof(log_data), PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow);
// AddLog(LOG_LEVEL_DEBUG);
if (0 == mrow) { // Default only 8 lines
mrow = 8;
}
if (srow > maxrow) {
srow = maxrow - mrow;
}
if (mrow < (maxrow - srow)) {
maxrow = srow + mrow;
}
for (row = srow; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (col = 0; col < CFG_COLS; col++) {
// if (!(col%4)) {
// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
// }
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data);
AddLog(LOG_LEVEL_INFO);
delay(1);
}
}
void DebugCfgPeek(char* parms)
{
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
address = (address >> 2) << 2;
uint8_t *buffer = (uint8_t *) &Settings;
uint8_t data8 = buffer[address];
uint16_t data16 = (buffer[address +1] << 8) + buffer[address];
uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + data16;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), address);
for (byte i = 0; i < 4; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[address +i]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (byte i = 0; i < 4; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[address +i] > 0x20) && (buffer[address +i] < 0x7F)) ? (char)buffer[address +i] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s| 0x%02X (%d), 0x%04X (%d), 0x%0LX (%lu)"), log_data, data8, data8, data16, data16, data32, data32);
AddLog(LOG_LEVEL_INFO);
}
void DebugCfgPoke(char* parms)
{
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
address = (address >> 2) << 2;
uint32_t data = strtol(p, &p, 16);
uint8_t *buffer = (uint8_t *) &Settings;
uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address];
uint8_t *nbuffer = (uint8_t *) &data;
for (byte i = 0; i < 4; i++) { buffer[address +i] = nbuffer[+i]; }
uint32_t ndata32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address];
snprintf_P(log_data, sizeof(log_data), PSTR("%03X: 0x%0LX (%lu) poked to 0x%0LX (%lu)"), address, data32, data32, ndata32, ndata32);
AddLog(LOG_LEVEL_INFO);
}
/*******************************************************************************************/
boolean DebugCommand()
{
char command[CMDSZ];
boolean serviced = true;
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kDebugCommands);
if (-1 == command_code) {
serviced = false; // Unknown command
}
else if (CMND_CFGDUMP == command_code) {
DebugCfgDump(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_CFGPEEK == command_code) {
DebugCfgPeek(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
else if (CMND_CFGPOKE == command_code) {
DebugCfgPoke(XdrvMailbox.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
#ifdef USE_WEBSERVER
else if (CMND_CFGXOR == command_code) {
if (XdrvMailbox.data_len > 0) {
config_xor_on_set = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, config_xor_on_set);
}
#endif // USE_WEBSERVER
#ifdef DEBUG_THEO
else if (CMND_EXCEPTION == command_code) {
if (XdrvMailbox.data_len > 0) ExceptionTest(XdrvMailbox.payload);
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
#endif // DEBUG_THEO
else if (CMND_CPUCHECK == command_code) {
if (XdrvMailbox.data_len > 0) {
CPU_load_check = XdrvMailbox.payload;
CPU_last_millis = CPU_last_loop_time;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, CPU_load_check);
}
else serviced = false; // Unknown command
return serviced;
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XDRV_99
boolean Xdrv99(byte function)
{
boolean result = false;
switch (function) {
case FUNC_PRE_INIT:
CPU_last_millis = millis();
break;
case FUNC_LOOP:
CpuLoadLoop();
break;
case FUNC_COMMAND:
result = DebugCommand();
break;
case FUNC_FREE_MEM:
DebugFreeMem();
break;
}
return result;
}
#endif // USE_DEBUG_DRIVER

View File

@ -1,262 +0,0 @@
/*
xdsp_01_lcd.ino - Display LCD support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_I2C
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_LCD
#define XDSP_01 1
#define LCD_ADDRESS1 0x27 // LCD I2C address option 1
#define LCD_ADDRESS2 0x3F // LCD I2C address option 2
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C *lcd;
/*********************************************************************************************/
void LcdInitMode()
{
lcd->init();
lcd->clear();
}
void LcdInit(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
LcdInitMode();
#ifdef USE_DISPLAY_MODES1TO5
DisplayClearScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void LcdInitDriver()
{
if (!Settings.display_model) {
if (I2cDevice(LCD_ADDRESS1)) {
Settings.display_address[0] = LCD_ADDRESS1;
Settings.display_model = XDSP_01;
}
else if (I2cDevice(LCD_ADDRESS2)) {
Settings.display_address[0] = LCD_ADDRESS2;
Settings.display_model = XDSP_01;
}
}
if (XDSP_01 == Settings.display_model) {
lcd = new LiquidCrystal_I2C(Settings.display_address[0], Settings.display_cols[0], Settings.display_rows);
#ifdef USE_DISPLAY_MODES1TO5
DisplayAllocScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
LcdInitMode();
}
}
void LcdDrawStringAt()
{
lcd->setCursor(dsp_x, dsp_y);
lcd->print(dsp_str);
}
void LcdDisplayOnOff(uint8_t on)
{
if (on) {
lcd->backlight();
} else {
lcd->noBacklight();
}
}
/*********************************************************************************************/
#ifdef USE_DISPLAY_MODES1TO5
void LcdCenter(byte row, char* txt)
{
int offset;
int len;
char line[Settings.display_cols[0] +2];
memset(line, 0x20, Settings.display_cols[0]);
line[Settings.display_cols[0]] = 0;
len = strlen(txt);
offset = (len < Settings.display_cols[0]) ? offset = (Settings.display_cols[0] - len) / 2 : 0;
strncpy(line +offset, txt, len);
lcd->setCursor(0, row);
lcd->print(line);
}
void LcdPrintLogLine()
{
if (!disp_screen_buffer_cols) {
DisplayAllocScreenBuffer();
} else {
uint8_t last_row = Settings.display_rows -1;
for (byte i = 0; i < last_row; i++) {
strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols);
lcd->setCursor(0, i); // Col 0, Row i
lcd->print(disp_screen_buffer[i +1]);
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\337'; // = 0xDF
}
strlcpy(disp_screen_buffer[last_row], disp_log_buffer[disp_log_buffer_ptr], disp_screen_buffer_cols);
// Fill with spaces
byte len = disp_screen_buffer_cols - strlen(disp_screen_buffer[last_row]);
if (len) {
memset(disp_screen_buffer[last_row] + strlen(disp_screen_buffer[last_row]), 0x20, len);
disp_screen_buffer[last_row][disp_screen_buffer_cols -1] = 0;
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
lcd->setCursor(0, last_row);
lcd->print(disp_screen_buffer[last_row]);
}
}
void LcdPrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
LcdPrintLogLine();
DisplayLogBufferPtrInc();
}
}
}
void LcdTime()
{
char line[Settings.display_cols[0] +1];
snprintf_P(line, sizeof(line), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
LcdCenter(0, line);
snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year);
LcdCenter(1, line);
}
void LcdRefresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
switch (Settings.display_mode) {
case 1: // Time
LcdTime();
break;
case 2: // Local
case 4: // Mqtt
LcdPrintLog();
break;
case 3: // Local
case 5: { // Mqtt
LcdPrintLog();
if (!disp_log_buffer_active) {
LcdTime();
}
break;
}
}
}
}
#endif // USE_DISPLAY_MODES1TO5
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp01(byte function)
{
boolean result = false;
if (i2c_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
LcdInitDriver();
}
else if (XDSP_01 == Settings.display_model) {
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
LcdInit(dsp_init);
break;
case FUNC_DISPLAY_POWER:
LcdDisplayOnOff(disp_power);
break;
case FUNC_DISPLAY_CLEAR:
lcd->clear();
break;
// case FUNC_DISPLAY_DRAW_HLINE:
// break;
// case FUNC_DISPLAY_DRAW_VLINE:
// break;
// case FUNC_DISPLAY_DRAW_CIRCLE:
// break;
// case FUNC_DISPLAY_FILL_CIRCLE:
// break;
// case FUNC_DISPLAY_DRAW_RECTANGLE:
// break;
// case FUNC_DISPLAY_FILL_RECTANGLE:
// break;
// case FUNC_DISPLAY_DRAW_FRAME:
// break;
// case FUNC_DISPLAY_TEXT_SIZE:
// break;
// case FUNC_DISPLAY_FONT_SIZE:
// break;
case FUNC_DISPLAY_DRAW_STRING:
LcdDrawStringAt();
break;
case FUNC_DISPLAY_ONOFF:
LcdDisplayOnOff(dsp_on);
break;
// case FUNC_DISPLAY_ROTATION:
// break;
#ifdef USE_DISPLAY_MODES1TO5
case FUNC_DISPLAY_EVERY_SECOND:
LcdRefresh();
break;
#endif // USE_DISPLAY_MODES1TO5
}
}
}
return result;
}
#endif // USE_DISPLAY_LCD
#endif // USE_DISPLAY
#endif // USE_I2C

View File

@ -1,300 +0,0 @@
/*
xdsp_02_ssd1306.ino - Display Oled ssd1306 support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_I2C
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_SSD1306
#define XDSP_02 2
#define OLED_ADDRESS1 0x3C // Oled 128x32 I2C address
#define OLED_ADDRESS2 0x3D // Oled 128x64 I2C address
#define OLED_FONT_WIDTH 6
#define OLED_FONT_HEIGTH 8
//#define OLED_BUFFER_COLS 21 or 11 // Max number of columns in display shadow buffer
//#define OLED_BUFFER_ROWS 8 or 16 // Max number of lines in display shadow buffer
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 *oled;
uint8_t ssd1306_font_x = OLED_FONT_WIDTH;
uint8_t ssd1306_font_y = OLED_FONT_HEIGTH;
/*********************************************************************************************/
void Ssd1306InitMode()
{
oled->setRotation(Settings.display_rotate); // 0
oled->invertDisplay(false);
oled->clearDisplay();
oled->setTextWrap(false); // Allow text to run off edges
oled->cp437(true);
oled->setTextSize(Settings.display_size);
oled->setTextColor(WHITE);
oled->setCursor(0,0);
oled->display();
}
void Ssd1306Init(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
Ssd1306InitMode();
#ifdef USE_DISPLAY_MODES1TO5
DisplayClearScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void Ssd1306InitDriver()
{
if (!Settings.display_model) {
if (I2cDevice(OLED_ADDRESS1)) {
Settings.display_address[0] = OLED_ADDRESS1;
Settings.display_model = XDSP_02;
}
else if (I2cDevice(OLED_ADDRESS2)) {
Settings.display_address[0] = OLED_ADDRESS2;
Settings.display_model = XDSP_02;
}
}
if (XDSP_02 == Settings.display_model) {
oled = new Adafruit_SSD1306();
oled->begin(SSD1306_SWITCHCAPVCC, Settings.display_address[0]);
#ifdef USE_DISPLAY_MODES1TO5
DisplayAllocScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
Ssd1306InitMode();
}
}
void Ssd1306Clear()
{
oled->clearDisplay();
oled->setCursor(0, 0);
oled->display();
}
void Ssd1306DrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
{
if (!flag) {
oled->setCursor(x, y);
} else {
oled->setCursor((x-1) * ssd1306_font_x * Settings.display_size, (y-1) * ssd1306_font_y * Settings.display_size);
}
oled->println(str);
}
void Ssd1306DisplayOnOff(uint8_t on)
{
if (on) {
oled->ssd1306_command(SSD1306_DISPLAYON);
} else {
oled->ssd1306_command(SSD1306_DISPLAYOFF);
}
}
void Ssd1306OnOff()
{
Ssd1306DisplayOnOff(disp_power);
oled->display();
}
/*********************************************************************************************/
#ifdef USE_DISPLAY_MODES1TO5
void Ssd1306PrintLogLine()
{
if (!disp_screen_buffer_cols) {
DisplayAllocScreenBuffer();
} else {
uint8_t last_row = Settings.display_rows -1;
oled->clearDisplay();
oled->setTextSize(Settings.display_size);
oled->setCursor(0,0);
for (byte i = 0; i < last_row; i++) {
strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols);
oled->println(disp_screen_buffer[i]);
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
strlcpy(disp_screen_buffer[last_row], disp_log_buffer[disp_log_buffer_ptr], disp_screen_buffer_cols);
// Fill with spaces
byte len = disp_screen_buffer_cols - strlen(disp_screen_buffer[last_row]);
if (len) {
memset(disp_screen_buffer[last_row] + strlen(disp_screen_buffer[last_row]), 0x20, len);
disp_screen_buffer[last_row][disp_screen_buffer_cols -1] = 0;
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
oled->println(disp_screen_buffer[last_row]);
oled->display();
}
}
void Ssd1306PrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
Ssd1306PrintLogLine();
DisplayLogBufferPtrInc();
}
}
}
void Ssd1306Time()
{
char line[12];
oled->clearDisplay();
oled->setTextSize(2);
oled->setCursor(0, 0);
snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); // [ 12:34:56 ]
oled->println(line);
snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [01-02-2018]
oled->println(line);
oled->display();
}
void Ssd1306Refresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
switch (Settings.display_mode) {
case 1: // Time
Ssd1306Time();
break;
case 2: // Local
case 3: // Local
case 4: // Mqtt
case 5: // Mqtt
Ssd1306PrintLog();
break;
}
}
}
#endif // USE_DISPLAY_MODES1TO5
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp02(byte function)
{
boolean result = false;
if (i2c_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
Ssd1306InitDriver();
}
else if (XDSP_02 == Settings.display_model) {
if (!dsp_color) { dsp_color = WHITE; }
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
Ssd1306Init(dsp_init);
break;
case FUNC_DISPLAY_POWER:
Ssd1306OnOff();
break;
case FUNC_DISPLAY_CLEAR:
Ssd1306Clear();
break;
case FUNC_DISPLAY_DRAW_HLINE:
oled->writeFastHLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_VLINE:
oled->writeFastVLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_LINE:
oled->writeLine(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_CIRCLE:
oled->drawCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_FILL_CIRCLE:
oled->fillCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_DRAW_RECTANGLE:
oled->drawRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_FILL_RECTANGLE:
oled->fillRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_FRAME:
oled->display();
break;
case FUNC_DISPLAY_TEXT_SIZE:
oled->setTextSize(Settings.display_size);
break;
case FUNC_DISPLAY_FONT_SIZE:
// oled->setTextSize(Settings.display_font);
break;
case FUNC_DISPLAY_DRAW_STRING:
Ssd1306DrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag);
break;
case FUNC_DISPLAY_ONOFF:
Ssd1306DisplayOnOff(dsp_on);
break;
case FUNC_DISPLAY_ROTATION:
oled->setRotation(Settings.display_rotate);
break;
#ifdef USE_DISPLAY_MODES1TO5
case FUNC_DISPLAY_EVERY_SECOND:
Ssd1306Refresh();
break;
#endif // USE_DISPLAY_MODES1TO5
}
}
}
return result;
}
#endif // USE_DISPLAY_SSD1306
#endif // USE_DISPLAY
#endif // USE_I2C

View File

@ -1,361 +0,0 @@
/*
xdsp_03_matrix.ino - Display 8x8 matrix support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_I2C
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_MATRIX
#define XDSP_03 3
#define MTX_MAX_SCREEN_BUFFER 80
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h> // 8x8 Matrix
Adafruit_8x8matrix *matrix[8];
uint8_t mtx_matrices = 0;
uint8_t mtx_state = 0;
uint8_t mtx_counter = 0;
int16_t mtx_x = 0;
int16_t mtx_y = 0;
char mtx_buffer[MTX_MAX_SCREEN_BUFFER];
uint8_t mtx_mode = 0;
uint8_t mtx_loop = 0;
/*********************************************************************************************/
void MatrixWrite()
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->writeDisplay();
}
}
void MatrixClear()
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
}
MatrixWrite();
}
void MatrixFixed(char* txt)
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
matrix[i]->setCursor(-i *8, 0);
matrix[i]->print(txt);
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
}
void MatrixCenter(char* txt)
{
int offset;
int len = strlen(txt);
offset = (len < 8) ? offset = ((mtx_matrices *8) - (len *6)) / 2 : 0;
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
matrix[i]->setCursor(-(i *8)+offset, 0);
matrix[i]->print(txt);
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
}
void MatrixScrollLeft(char* txt, int loop)
{
switch (mtx_state) {
case 1:
mtx_state = 2;
// Horiz. position of text -- starts off right edge
mtx_x = 8 * mtx_matrices;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), txt);
AddLog(LOG_LEVEL_DEBUG);
disp_refresh = Settings.display_refresh;
case 2:
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
matrix[i]->setCursor(mtx_x - i *8, 0);
matrix[i]->print(txt);
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
// Move text position left by 1 pixel.
mtx_x--;
int16_t len = strlen(txt);
if (mtx_x < -(len *6)) {
mtx_state = loop;
}
}
break;
}
}
void MatrixScrollUp(char* txt, int loop)
{
int wordcounter = 0;
char tmpbuf[200];
char *words[100];
// char separators[] = " ,.;:!?";
// char separators[] = " ";
// char separators[] = " /|";
char separators[] = " /";
switch (mtx_state) {
case 1:
mtx_state = 2;
// Vertical position of text -- starts off left bottom edge
mtx_y = 8;
mtx_counter = 0;
disp_refresh = Settings.display_refresh;
case 2:
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
strlcpy(tmpbuf, txt, sizeof(tmpbuf));
char *p = strtok(tmpbuf, separators);
while (p != NULL && wordcounter < 40) {
words[wordcounter++] = p;
p = strtok(NULL, separators);
}
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
for (byte j = 0; j < wordcounter; j++) {
matrix[i]->setCursor(-i *8, mtx_y + (j *8));
matrix[i]->println(words[j]);
}
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
if (((mtx_y %8) == 0) && mtx_counter) {
mtx_counter--;
} else {
mtx_y--; // Move text position up by 1 pixel.
mtx_counter = STATES * 1; // Hold text for 1 seconds
}
if (mtx_y < -(wordcounter *8)) {
mtx_state = loop;
}
}
break;
}
}
/*********************************************************************************************/
void MatrixInitMode()
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->setRotation(Settings.display_rotate); // 1
matrix[i]->setBrightness(Settings.display_dimmer);
matrix[i]->blinkRate(0); // 0 - 3
matrix[i]->setTextWrap(false); // Allow text to run off edges
// matrix[i]->setTextSize(Settings.display_size);
// matrix[i]->setTextColor(LED_RED);
matrix[i]->cp437(true);
}
MatrixClear();
}
void MatrixInit(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
MatrixInitMode();
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void MatrixInitDriver()
{
if (!Settings.display_model) {
if (I2cDevice(Settings.display_address[1])) {
Settings.display_model = XDSP_03;
}
}
if (XDSP_03 == Settings.display_model) {
mtx_state = 1;
for (mtx_matrices = 0; mtx_matrices < 8; mtx_matrices++) {
if (Settings.display_address[mtx_matrices]) {
matrix[mtx_matrices] = new Adafruit_8x8matrix();
matrix[mtx_matrices]->begin(Settings.display_address[mtx_matrices]);
} else {
break;
}
}
MatrixInitMode();
}
}
void MatrixOnOff()
{
if (!disp_power) {
MatrixClear();
}
}
void MatrixDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
{
snprintf(mtx_buffer, sizeof(mtx_buffer), str);
mtx_mode = x;
mtx_loop = y;
if (!mtx_state) { mtx_state = 1; }
}
/*********************************************************************************************/
#ifdef USE_DISPLAY_MODES1TO5
void MatrixBufferScroll(uint8_t direction)
{
if (disp_log_buffer_idx != disp_log_buffer_ptr) {
if (!mtx_state) {
mtx_state = 1;
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
if (direction) {
MatrixScrollUp(disp_log_buffer[disp_log_buffer_ptr], 0);
} else {
// Remove extra spaces
uint8_t space = 0;
uint8_t max_cols = (disp_log_buffer_cols < MTX_MAX_SCREEN_BUFFER) ? disp_log_buffer_cols : MTX_MAX_SCREEN_BUFFER;
mtx_buffer[0] = '\0';
for (byte i = 0; i < max_cols; i++) {
if (disp_log_buffer[disp_log_buffer_ptr][i] == ' ') {
space++;
} else {
space = 0;
}
if (space < 2) {
strncat(mtx_buffer, (const char*)disp_log_buffer[disp_log_buffer_ptr] +i, 1);
}
}
MatrixScrollLeft(mtx_buffer, 0);
}
if (!mtx_state) {
DisplayLogBufferPtrInc();
}
} else {
char disp_time[9]; // 13:45:43
snprintf_P(disp_time, sizeof(disp_time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
MatrixFixed(disp_time);
}
}
#endif // USE_DISPLAY_MODES1TO5
void MatrixRefresh() // Every second
{
if (disp_power) {
switch (Settings.display_mode) {
case 0: {
switch (mtx_mode) {
case 0:
MatrixScrollLeft(mtx_buffer, mtx_loop);
break;
case 1:
MatrixScrollUp(mtx_buffer, mtx_loop);
break;
}
break;
}
#ifdef USE_DISPLAY_MODES1TO5
case 2: {
char disp_date[9]; // 24-04-17
snprintf_P(disp_date, sizeof(disp_date), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year -2000);
MatrixFixed(disp_date);
break;
}
case 3: {
char disp_day[10]; // Mon
snprintf_P(disp_day, sizeof(disp_day), PSTR("%d %s"), RtcTime.day_of_month, RtcTime.name_of_month);
MatrixCenter(disp_day);
break;
}
case 4:
MatrixBufferScroll(0);
break;
case 1: // Time and user text
case 5: // Time, user text and MQTT
MatrixBufferScroll(1);
break;
#endif // USE_DISPLAY_MODES1TO5
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp03(byte function)
{
boolean result = false;
if (i2c_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
MatrixInitDriver();
}
else if (XDSP_03 == Settings.display_model) {
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
MatrixInit(dsp_init);
break;
case FUNC_DISPLAY_EVERY_50_MSECOND:
MatrixRefresh();
break;
case FUNC_DISPLAY_POWER:
MatrixOnOff();
break;
case FUNC_DISPLAY_DRAW_STRING:
MatrixDrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag);
break;
}
}
}
return result;
}
#endif // USE_DISPLAY_MATRIX
#endif // USE_DISPLAY
#endif // USE_I2C

View File

@ -1,279 +0,0 @@
/*
xdsp_04_ili9341.ino - Display Tft Ili9341 support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_SPI
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_ILI9341
#define XDSP_04 4
#define TFT_TOP 16
#define TFT_BOTTOM 16
#define TFT_FONT_WIDTH 6
#define TFT_FONT_HEIGTH 8 // Adafruit minimal font heigth pixels
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h> // TFT 320x240 and 480x320
Adafruit_ILI9341 *tft;
uint16_t tft_scroll;
/*********************************************************************************************/
void Ili9341InitMode()
{
tft->setRotation(Settings.display_rotate); // 0
tft->invertDisplay(0);
tft->fillScreen(ILI9341_BLACK);
tft->setTextWrap(false); // Allow text to run off edges
tft->cp437(true);
if (!Settings.display_mode) {
tft->setCursor(0, 0);
tft->setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft->setTextSize(1);
} else {
tft->setScrollMargins(TFT_TOP, TFT_BOTTOM);
tft->setCursor(0, 0);
tft->setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft->setTextSize(2);
tft->println("HEADER");
tft_scroll = TFT_TOP;
}
}
void Ili9341Init(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
Ili9341InitMode();
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void Ili9341InitDriver()
{
if (!Settings.display_model) {
Settings.display_model = XDSP_04;
}
if (XDSP_04 == Settings.display_model) {
tft = new Adafruit_ILI9341(pin[GPIO_SPI_CS], pin[GPIO_SPI_DC]);
tft->begin();
Ili9341InitMode();
}
}
void Ili9341Clear()
{
tft->fillScreen(ILI9341_BLACK);
tft->setCursor(0, 0);
}
void Ili9341DrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
{
uint16_t active_color = ILI9341_WHITE;
tft->setTextSize(Settings.display_size);
if (!flag) {
tft->setCursor(x, y);
} else {
tft->setCursor((x-1) * TFT_FONT_WIDTH * Settings.display_size, (y-1) * TFT_FONT_HEIGTH * Settings.display_size);
}
if (color) { active_color = color; }
tft->setTextColor(active_color, ILI9341_BLACK);
tft->println(str);
}
void Ili9341DisplayOnOff(uint8_t on)
{
// tft->showDisplay(on);
// tft->invertDisplay(on);
if (pin[GPIO_BACKLIGHT] < 99) {
pinMode(pin[GPIO_BACKLIGHT], OUTPUT);
digitalWrite(pin[GPIO_BACKLIGHT], on);
}
}
void Ili9341OnOff()
{
Ili9341DisplayOnOff(disp_power);
}
/*********************************************************************************************/
#ifdef USE_DISPLAY_MODES1TO5
void Ili9341PrintLogLine()
{
tft->setTextColor(ILI9341_CYAN, ILI9341_BLACK); // Add background color to solve flicker
tft->setCursor(0, tft_scroll);
byte size = Settings.display_size;
tft->setTextSize(size);
uint16_t theight = size * TFT_FONT_HEIGTH;
tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK); // Erase line
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), disp_log_buffer[disp_log_buffer_ptr]);
AddLog(LOG_LEVEL_DEBUG);
tft->print(disp_log_buffer[disp_log_buffer_ptr]);
tft_scroll += theight;
if (tft_scroll >= (tft->height() - TFT_BOTTOM)) {
tft_scroll = TFT_TOP;
}
tft->scrollTo(tft_scroll);
}
void Ili9341PrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
Ili9341PrintLogLine();
DisplayLogBufferPtrInc();
}
}
}
void Ili9341Refresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
char tftdt[21];
char disp_time[9]; // 13:45:43
char disp_date4[11]; // 24-04-2017
snprintf_P(disp_time, sizeof(disp_time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
snprintf_P(disp_date4, sizeof(disp_date4), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year);
tft->setTextSize(2);
tft->setTextColor(ILI9341_YELLOW, ILI9341_BLACK); // Add background color to solve flicker
tft->setCursor(0, 0);
snprintf_P(tftdt, sizeof(tftdt), PSTR("%s %s"), disp_date4, disp_time);
tft->print(tftdt);
switch (Settings.display_mode) {
case 1: // Text
case 2: // Local
case 3: // Local
case 4: // Mqtt
case 5: // Mqtt
Ili9341PrintLog();
break;
}
}
}
#endif // USE_DISPLAY_MODES1TO5
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp04(byte function)
{
boolean result = false;
if (spi_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
Ili9341InitDriver();
}
else if (XDSP_04 == Settings.display_model) {
if (!dsp_color) { dsp_color = ILI9341_WHITE; }
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
Ili9341Init(dsp_init);
break;
case FUNC_DISPLAY_POWER:
Ili9341OnOff();
break;
case FUNC_DISPLAY_CLEAR:
Ili9341Clear();
break;
case FUNC_DISPLAY_DRAW_HLINE:
tft->writeFastHLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_VLINE:
tft->writeFastVLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_LINE:
tft->writeLine(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_CIRCLE:
tft->drawCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_FILL_CIRCLE:
tft->fillCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_DRAW_RECTANGLE:
tft->drawRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_FILL_RECTANGLE:
tft->fillRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
// case FUNC_DISPLAY_DRAW_FRAME:
// oled->display();
// break;
case FUNC_DISPLAY_TEXT_SIZE:
tft->setTextSize(Settings.display_size);
break;
case FUNC_DISPLAY_FONT_SIZE:
// tft->setTextSize(Settings.display_font);
break;
case FUNC_DISPLAY_DRAW_STRING:
Ili9341DrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag);
break;
case FUNC_DISPLAY_ONOFF:
Ili9341DisplayOnOff(dsp_on);
break;
case FUNC_DISPLAY_ROTATION:
tft->setRotation(Settings.display_rotate);
break;
#ifdef USE_DISPLAY_MODES1TO5
case FUNC_DISPLAY_EVERY_SECOND:
Ili9341Refresh();
break;
#endif // USE_DISPLAY_MODES1TO5
}
}
}
return result;
}
#endif // USE_DISPLAY_ILI9341
#endif // USE_DISPLAY
#endif // USE_SPI

View File

@ -1,261 +0,0 @@
/*
xdsp_05_epaper.ino - Display e-paper support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends, Gerhard Mutz and Waveshare
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/>.
*/
#ifdef USE_SPI
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_EPAPER
#define XDSP_05 5
#define COLORED 0
#define UNCOLORED 1
// using font 8 is opional (num=3)
// very badly readable, but may be useful for graphs
#define USE_TINY_FONT
#include <epd2in9.h>
#include <epdpaint.h>
unsigned char image[(EPD_HEIGHT * EPD_WIDTH) / 8];
Paint paint(image, EPD_WIDTH, EPD_HEIGHT); // width should be the multiple of 8
Epd epd;
sFONT *selected_font;
/*********************************************************************************************/
void EpdInitMode()
{
// whiten display with full update
epd.Init(lut_full_update);
epd.ClearFrameMemory(0xFF); // bit set = white, bit reset = black
epd.DisplayFrame();
delay(3000);
// switch to partial update
epd.Init(lut_partial_update);
// Clear image memory
epd.ClearFrameMemory(0xFF); // bit set = white, bit reset = black
epd.DisplayFrame();
delay(500);
selected_font = &Font12;
paint.SetRotate(Settings.display_rotate);
/*
// Welcome text
paint.Clear(UNCOLORED);
paint.DrawStringAt(50, 50, "Waveshare E-Paper Display!", selected_font, COLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
epd.DisplayFrame();
delay(1000);
*/
paint.Clear(UNCOLORED);
}
void EpdInitPartial()
{
epd.Init(lut_partial_update);
//paint.Clear(UNCOLORED);
epd.DisplayFrame();
delay(500);
}
void EpdInitFull()
{
epd.Init(lut_full_update);
//paint.Clear(UNCOLORED);
//epd.ClearFrameMemory(0xFF);
epd.DisplayFrame();
delay(3000);
}
void EpdInit(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
EpdInitMode();
break;
case DISPLAY_INIT_PARTIAL:
EpdInitPartial();
break;
case DISPLAY_INIT_FULL:
EpdInitFull();
break;
}
}
void EpdInitDriver()
{
if (!Settings.display_model) {
Settings.display_model = XDSP_05;
}
if (XDSP_05 == Settings.display_model) {
epd.cs_pin = pin[GPIO_SPI_CS];
epd.mosi_pin = pin[GPIO_SPI_MOSI]; // 13
epd.sclk_pin = pin[GPIO_SPI_CLK]; // 14
EpdInitMode();
}
}
/*********************************************************************************************/
void EpdClear()
{
paint.Clear(UNCOLORED);
}
void EpdSetFont(uint8_t font)
{
if (1 == font) {
selected_font = &Font12;
} else {
#ifdef USE_TINY_FONT
if (2 == font) {
selected_font = &Font24;
} else {
selected_font = &Font8;
}
#else
selected_font = &Font24;
#endif
}
}
void EpdDrawStringAt(uint16_t x, uint16_t y, char *str, uint8_t color, uint8_t flag)
{
if (!flag) {
paint.DrawStringAt(x, y, str, selected_font, color);
} else {
paint.DrawStringAt((x-1) * selected_font->Width, (y-1) * selected_font->Height, str, selected_font, color);
}
}
// not needed
void EpdDisplayOnOff(uint8_t on)
{
}
void EpdOnOff()
{
EpdDisplayOnOff(disp_power);
}
/*********************************************************************************************/
#ifdef USE_DISPLAY_MODES1TO5
void EpdRefresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
}
}
#endif // USE_DISPLAY_MODES1TO5
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp05(byte function)
{
boolean result = false;
if (spi_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
EpdInitDriver();
}
else if (XDSP_04 == Settings.display_model) {
if (!dsp_color) { dsp_color = COLORED; }
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
EpdInit(dsp_init);
break;
case FUNC_DISPLAY_POWER:
EpdOnOff();
break;
case FUNC_DISPLAY_CLEAR:
EpdClear();
break;
case FUNC_DISPLAY_DRAW_HLINE:
paint.DrawHorizontalLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_VLINE:
paint.DrawVerticalLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_LINE:
paint.DrawLine(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_CIRCLE:
paint.DrawCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_FILL_CIRCLE:
paint.DrawFilledCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_DRAW_RECTANGLE:
paint.DrawRectangle(dsp_x, dsp_y, dsp_x + dsp_x2, dsp_y + dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_FILL_RECTANGLE:
paint.DrawFilledRectangle(dsp_x, dsp_y, dsp_x + dsp_x2, dsp_y + dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_FRAME:
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
epd.DisplayFrame();
break;
case FUNC_DISPLAY_TEXT_SIZE:
// EpdSetFontorSize(Settings.display_size);
break;
case FUNC_DISPLAY_FONT_SIZE:
EpdSetFont(Settings.display_font);
break;
case FUNC_DISPLAY_DRAW_STRING:
EpdDrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag);
break;
case FUNC_DISPLAY_ONOFF:
EpdDisplayOnOff(dsp_on);
break;
case FUNC_DISPLAY_ROTATION:
paint.SetRotate(Settings.display_rotate);
break;
#ifdef USE_DISPLAY_MODES1TO5
case FUNC_DISPLAY_EVERY_SECOND:
EpdRefresh();
break;
#endif // USE_DISPLAY_MODES1TO5
}
}
}
return result;
}
#endif // USE_DISPLAY_EPAPER
#endif // USE_DISPLAY
#endif // USE_SPI

View File

@ -1,125 +0,0 @@
/*
xdsp_interface.ino - Display interface support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
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/>.
*/
boolean (* const xdsp_func_ptr[])(byte) PROGMEM = { // Display Function Pointers
#ifdef XDSP_01
&Xdsp01,
#endif
#ifdef XDSP_02
&Xdsp02,
#endif
#ifdef XDSP_03
&Xdsp03,
#endif
#ifdef XDSP_04
&Xdsp04,
#endif
#ifdef XDSP_05
&Xdsp05,
#endif
#ifdef XDSP_06
&Xdsp06,
#endif
#ifdef XDSP_07
&Xdsp07,
#endif
#ifdef XDSP_08
&Xdsp08,
#endif
#ifdef XDSP_09
&Xdsp09,
#endif
#ifdef XDSP_10
&Xdsp10,
#endif
#ifdef XDSP_11
&Xdsp11,
#endif
#ifdef XDSP_12
&Xdsp12,
#endif
#ifdef XDSP_13
&Xdsp13,
#endif
#ifdef XDSP_14
&Xdsp14,
#endif
#ifdef XDSP_15
&Xdsp15,
#endif
#ifdef XDSP_16
&Xdsp16
#endif
};
const uint8_t xdsp_present = sizeof(xdsp_func_ptr) / sizeof(xdsp_func_ptr[0]); // Number of drivers found
/*********************************************************************************************\
* Function call to all xdsp
*
* FUNC_DISPLAY_INIT_DRIVER
* FUNC_DISPLAY_INIT
* FUNC_DISPLAY_EVERY_50_MSECOND
* FUNC_DISPLAY_EVERY_SECOND
* FUNC_DISPLAY_POWER
* FUNC_DISPLAY_CLEAR
* FUNC_DISPLAY_DRAW_FRAME
* FUNC_DISPLAY_DRAW_HLINE
* FUNC_DISPLAY_DRAW_VLINE
* FUNC_DISPLAY_DRAW_CIRCLE
* FUNC_DISPLAY_FILL_CIRCLE
* FUNC_DISPLAY_DRAW_RECTANGLE
* FUNC_DISPLAY_FILL_RECTANGLE
* FUNC_DISPLAY_FONT_SIZE
* FUNC_DISPLAY_ROTATION
* FUNC_DISPLAY_DRAW_STRING
* FUNC_DISPLAY_ONOFF
\*********************************************************************************************/
uint8_t XdspPresent()
{
return xdsp_present;
}
boolean XdspCall(byte Function)
{
boolean result = false;
for (byte x = 0; x < xdsp_present; x++) {
result = xdsp_func_ptr[x](Function);
if (result) break;
}
return result;
}

File diff suppressed because it is too large Load Diff