mirror of https://github.com/arendst/Tasmota.git
parent
624ee28db3
commit
06604b7f09
|
@ -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
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
Loading…
Reference in New Issue