diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h
index f351b547d..1bf322288 100644
--- a/sonoff/sonoff_version.h
+++ b/sonoff/sonoff_version.h
@@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
-#define VERSION 0x0601010D
+#define VERSION 0x06020000
#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"
diff --git a/sonoff/xdrv_13_display.ino b/sonoff/xdrv_13_display.ino
deleted file mode 100644
index 5642a4bcc..000000000
--- a/sonoff/xdrv_13_display.ino
+++ /dev/null
@@ -1,1079 +0,0 @@
-/*
- xdrv_13_display.ino - Display 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 .
-*/
-
-#if defined(USE_I2C) || defined(USE_SPI)
-#ifdef USE_DISPLAY
-
-#define DISPLAY_MAX_DRIVERS 16 // Max number of display drivers/models supported by xdsp_interface.ino
-#define DISPLAY_MAX_COLS 40 // Max number of columns allowed with command DisplayCols
-#define DISPLAY_MAX_ROWS 32 // Max number of lines allowed with command DisplayRows
-
-#define DISPLAY_LOG_ROWS 32 // Number of lines in display log buffer
-
-#define D_CMND_DISPLAY "Display"
-#define D_CMND_DISP_ADDRESS "Address"
-#define D_CMND_DISP_COLS "Cols"
-#define D_CMND_DISP_DIMMER "Dimmer"
-#define D_CMND_DISP_MODE "Mode"
-#define D_CMND_DISP_MODEL "Model"
-#define D_CMND_DISP_REFRESH "Refresh"
-#define D_CMND_DISP_ROWS "Rows"
-#define D_CMND_DISP_SIZE "Size"
-#define D_CMND_DISP_FONT "Font"
-#define D_CMND_DISP_ROTATE "Rotate"
-#define D_CMND_DISP_TEXT "Text"
-
-enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_EVERY_50_MSECOND, FUNC_DISPLAY_EVERY_SECOND,
- FUNC_DISPLAY_MODEL, FUNC_DISPLAY_MODE, FUNC_DISPLAY_POWER,
- FUNC_DISPLAY_CLEAR, FUNC_DISPLAY_DRAW_FRAME,
- FUNC_DISPLAY_DRAW_HLINE, FUNC_DISPLAY_DRAW_VLINE, FUNC_DISPLAY_DRAW_LINE,
- FUNC_DISPLAY_DRAW_CIRCLE, FUNC_DISPLAY_FILL_CIRCLE,
- FUNC_DISPLAY_DRAW_RECTANGLE, FUNC_DISPLAY_FILL_RECTANGLE,
- FUNC_DISPLAY_TEXT_SIZE, FUNC_DISPLAY_FONT_SIZE, FUNC_DISPLAY_ROTATION, FUNC_DISPLAY_DRAW_STRING, FUNC_DISPLAY_ONOFF };
-
-enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL };
-
-enum DisplayCommands { CMND_DISP_MODEL, CMND_DISP_MODE, CMND_DISP_REFRESH, CMND_DISP_DIMMER, CMND_DISP_COLS, CMND_DISP_ROWS,
- CMND_DISP_SIZE, CMND_DISP_FONT, CMND_DISP_ROTATE, CMND_DISP_TEXT, CMND_DISP_ADDRESS };
-const char kDisplayCommands[] PROGMEM =
- D_CMND_DISP_MODEL "|" D_CMND_DISP_MODE "|" D_CMND_DISP_REFRESH "|" D_CMND_DISP_DIMMER "|" D_CMND_DISP_COLS "|" D_CMND_DISP_ROWS "|"
- D_CMND_DISP_SIZE "|" D_CMND_DISP_FONT "|" D_CMND_DISP_ROTATE "|" D_CMND_DISP_TEXT "|" D_CMND_DISP_ADDRESS ;
-
-const char S_JSON_DISPLAY_COMMAND_VALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s\":\"%s\"}";
-const char S_JSON_DISPLAY_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s\":%d}";
-const char S_JSON_DISPLAY_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s%d\":%d}";
-
-uint8_t disp_power = 0;
-uint8_t disp_device = 0;
-uint8_t disp_refresh = 1;
-
-int16_t disp_xpos = 0;
-int16_t disp_ypos = 0;
-uint8_t disp_autodraw = 1;
-
-uint8_t dsp_init;
-uint8_t dsp_font;
-uint8_t dsp_flag;
-uint8_t dsp_on;
-uint16_t dsp_x;
-uint16_t dsp_y;
-uint16_t dsp_x2;
-uint16_t dsp_y2;
-uint16_t dsp_rad;
-uint16_t dsp_color;
-int16_t dsp_len;
-char *dsp_str;
-
-#ifdef USE_DISPLAY_MODES1TO5
-
-char disp_temp[2]; // C or F
-uint8_t disp_subscribed = 0;
-
-char **disp_log_buffer;
-uint8_t disp_log_buffer_cols = 0;
-uint8_t disp_log_buffer_idx = 0;
-uint8_t disp_log_buffer_ptr = 0;
-bool disp_log_buffer_active = false;
-
-char **disp_screen_buffer;
-uint8_t disp_screen_buffer_cols = 0;
-uint8_t disp_screen_buffer_rows = 0;
-
-#endif // USE_DISPLAY_MODES1TO5
-
-/*********************************************************************************************/
-
-void DisplayInit(uint8_t mode)
-{
- dsp_init = mode;
- XdspCall(FUNC_DISPLAY_INIT);
-}
-
-void DisplayClear()
-{
- XdspCall(FUNC_DISPLAY_CLEAR);
-}
-
-void DisplayDrawHLine(uint16_t x, uint16_t y, int16_t len, uint16_t color)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_len = len;
- dsp_color = color;
- XdspCall(FUNC_DISPLAY_DRAW_HLINE);
-}
-
-void DisplayDrawVLine(uint16_t x, uint16_t y, int16_t len, uint16_t color)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_len = len;
- dsp_color = color;
- XdspCall(FUNC_DISPLAY_DRAW_VLINE);
-}
-
-void DisplayDrawLine(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_x2 = x2;
- dsp_y2 = y2;
- dsp_color = color;
- XdspCall(FUNC_DISPLAY_DRAW_LINE);
-}
-
-void DisplayDrawCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_rad = rad;
- dsp_color = color;
- XdspCall(FUNC_DISPLAY_DRAW_CIRCLE);
-}
-
-void DisplayDrawFilledCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_rad = rad;
- dsp_color = color;
- XdspCall(FUNC_DISPLAY_FILL_CIRCLE);
-}
-
-void DisplayDrawRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_x2 = x2;
- dsp_y2 = y2;
- dsp_color = color;
- XdspCall(FUNC_DISPLAY_DRAW_RECTANGLE);
-}
-
-void DisplayDrawFilledRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_x2 = x2;
- dsp_y2 = y2;
- dsp_color = color;
- XdspCall(FUNC_DISPLAY_FILL_RECTANGLE);
-}
-
-void DisplayDrawFrame()
-{
- XdspCall(FUNC_DISPLAY_DRAW_FRAME);
-}
-
-void DisplaySetSize(uint8_t size)
-{
- Settings.display_size = size &3;
- XdspCall(FUNC_DISPLAY_TEXT_SIZE);
-}
-
-void DisplaySetFont(uint8_t font)
-{
- Settings.display_font = font &3;
- XdspCall(FUNC_DISPLAY_FONT_SIZE);
-}
-
-void DisplaySetRotation(uint8_t rotation)
-{
- Settings.display_rotate = rotation &3;
- XdspCall(FUNC_DISPLAY_ROTATION);
-}
-
-void DisplayDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
-{
- dsp_x = x;
- dsp_y = y;
- dsp_str = str;
- dsp_color = color;
- dsp_flag = flag;
- XdspCall(FUNC_DISPLAY_DRAW_STRING);
-}
-
-void DisplayOnOff(uint8_t on)
-{
- dsp_on = on;
- XdspCall(FUNC_DISPLAY_ONOFF);
-}
-
-/*-------------------------------------------------------------------------------------------*/
-
-// get asci number until delimiter and return asci number lenght and value
-uint8_t atoiv(char *cp, int16_t *res)
-{
- uint8_t index = 0;
- *res = atoi(cp);
- while (*cp) {
- if ((*cp>='0' && *cp<='9') || (*cp=='-')) {
- cp++;
- index++;
- } else {
- break;
- }
- }
- return index;
-}
-
-// get asci number until delimiter and return asci number lenght and value
-uint8_t atoiV(char *cp, uint16_t *res)
-{
- uint8_t index = 0;
- *res = atoi(cp);
- while (*cp) {
- if (*cp>='0' && *cp<='9') {
- cp++;
- index++;
- } else {
- break;
- }
- }
- return index;
-}
-
-/*-------------------------------------------------------------------------------------------*/
-
-#define DISPLAY_BUFFER_COLS 128 // Max number of characters in linebuf
-
-void DisplayText()
-{
- uint8_t lpos;
- uint8_t escape = 0;
- uint8_t var;
- uint8_t font_x = 6;
- uint8_t font_y = 8;
- uint8_t fontnumber = 1;
- int16_t lin = 0;
- int16_t col = 0;
- int16_t fill = 0;
- int16_t temp;
- int16_t temp1;
- uint16_t color = 0;
-
- char linebuf[DISPLAY_BUFFER_COLS];
- char *dp = linebuf;
- char *cp = XdrvMailbox.data;
-
- memset(linebuf, ' ', sizeof(linebuf));
- linebuf[sizeof(linebuf)-1] = 0;
- *dp = 0;
-
- while (*cp) {
- if (!escape) {
- // check for escape
- if (*cp == '[') {
- escape = 1;
- cp++;
- // if string in buffer print it
- if ((uint32_t)dp - (uint32_t)linebuf) {
- if (!fill) { *dp = 0; }
- if (col > 0 && lin > 0) {
- // use col and lin
- DisplayDrawStringAt(col, lin, linebuf, color, 1);
- } else {
- // use disp_xpos, disp_ypos
- DisplayDrawStringAt(disp_xpos, disp_ypos, linebuf, color, 0);
- }
- memset(linebuf, ' ', sizeof(linebuf));
- linebuf[sizeof(linebuf)-1] = 0;
- dp = linebuf;
- }
- } else {
- // copy chars
- if (dp < (linebuf + DISPLAY_BUFFER_COLS)) { *dp++ = *cp++; }
- }
- } else {
- // check escapes
- if (*cp == ']') {
- escape = 0;
- cp++;
- } else {
- // analyze escapes
- switch (*cp++) {
- case 'z':
- // clear display
- DisplayClear();
- disp_xpos = 0;
- disp_ypos = 0;
- col = 0;
- lin = 0;
- break;
- case 'i':
- // init display with partial update
- DisplayInit(DISPLAY_INIT_PARTIAL);
- break;
- case 'I':
- // init display with full refresh
- DisplayInit(DISPLAY_INIT_FULL);
- break;
- case 'o':
- DisplayOnOff(0);
- break;
- case 'O':
- DisplayOnOff(1);
- break;
- case 'x':
- // set disp_xpos
- var = atoiv(cp, &disp_xpos);
- cp += var;
- break;
- case 'y':
- // set disp_ypos
- var = atoiv(cp, &disp_ypos);
- cp += var;
- break;
- case 'l':
- // text line lxx
- var = atoiv(cp, &lin);
- cp += var;
- //display.setCursor(display.getCursorX(),(lin-1)*font_y*txtsize);
- break;
- case 'c':
- // text column cxx
- var = atoiv(cp, &col);
- cp += var;
- //display.setCursor((col-1)*font_x*txtsize,display.getCursorY());
- break;
- case 'C':
- // text color cxx
- var = atoiV(cp, &color);
- cp += var;
- break;
- case 'p':
- // pad field with spaces fxx
- var = atoiv(cp, &fill);
- cp += var;
- linebuf[fill] = 0;
- break;
- case 'h':
- // hor line to
- var = atoiv(cp, &temp);
- cp += var;
- if (temp < 0) {
- DisplayDrawHLine(disp_xpos + temp, disp_ypos, -temp, color);
- } else {
- DisplayDrawHLine(disp_xpos, disp_ypos, temp, color);
- }
- disp_xpos += temp;
- break;
- case 'v':
- // vert line to
- var = atoiv(cp, &temp);
- cp += var;
- if (temp < 0) {
- DisplayDrawVLine(disp_xpos, disp_ypos + temp, -temp, color);
- } else {
- DisplayDrawVLine(disp_xpos, disp_ypos, temp, color);
- }
- disp_ypos += temp;
- break;
- case 'L':
- // any line to
- var = atoiv(cp, &temp);
- cp += var;
- cp++;
- var = atoiv(cp, &temp1);
- cp += var;
- DisplayDrawLine(disp_xpos, disp_ypos, temp, temp1, color);
- disp_xpos += temp;
- disp_ypos += temp1;
- break;
- case 'k':
- // circle
- var = atoiv(cp, &temp);
- cp += var;
- DisplayDrawCircle(disp_xpos, disp_ypos, temp, color);
- break;
- case 'K':
- // filled circle
- var = atoiv(cp, &temp);
- cp += var;
- DisplayDrawFilledCircle(disp_xpos, disp_ypos, temp, color);
- break;
- case 'r':
- // rectangle
- var = atoiv(cp, &temp);
- cp += var;
- cp++;
- var = atoiv(cp, &temp1);
- cp += var;
- DisplayDrawRectangle(disp_xpos, disp_ypos, temp, temp1, color);
- break;
- case 'R':
- // filled rectangle
- var = atoiv(cp, &temp);
- cp += var;
- cp++;
- var = atoiv(cp, &temp1);
- cp += var;
- DisplayDrawFilledRectangle(disp_xpos, disp_ypos, temp, temp1, color);
- break;
- case 't': {
- if (dp < (linebuf + DISPLAY_BUFFER_COLS) -5) {
- snprintf_P(dp, 5, PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute);
- dp += 5;
- }
- break;
- }
- case 'd':
- // force draw grafics buffer
- DisplayDrawFrame();
- break;
- case 'D':
- // set auto draw mode
- disp_autodraw = *cp&1;
- cp += 1;
- break;
- case 's':
- // size sx
- DisplaySetSize(*cp&3);
- cp += 1;
- break;
- case 'f':
- // font sx
- DisplaySetFont(*cp&3);
- cp += 1;
- break;
- case 'a':
- // rotation angle
- DisplaySetRotation(*cp&3);
- cp+=1;
- break;
- default:
- // unknown escape
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("Unknown Escape"));
- goto exit;
- break;
- }
- }
- }
- }
- exit:
- // now draw buffer
- if ((uint32_t)dp - (uint32_t)linebuf) {
- if (!fill) { *dp = 0; }
- if (col > 0 && lin > 0) {
- // use col and lin
- DisplayDrawStringAt(col, lin, linebuf, color, 1);
- } else {
- // use disp_xpos, disp_ypos
- DisplayDrawStringAt(disp_xpos, disp_ypos, linebuf, color, 0);
- }
- }
- // draw buffer
- if (disp_autodraw) { DisplayDrawFrame(); }
-}
-
-/*********************************************************************************************/
-
-#ifdef USE_DISPLAY_MODES1TO5
-
-void DisplayClearScreenBuffer()
-{
- if (disp_screen_buffer_cols) {
- for (byte i = 0; i < disp_screen_buffer_rows; i++) {
- memset(disp_screen_buffer[i], 0, disp_screen_buffer_cols);
- }
- }
-}
-
-void DisplayFreeScreenBuffer()
-{
- if (disp_screen_buffer != NULL) {
- for (byte i = 0; i < disp_screen_buffer_rows; i++) {
- if (disp_screen_buffer[i] != NULL) { free(disp_screen_buffer[i]); }
- }
- free(disp_screen_buffer);
- disp_screen_buffer_cols = 0;
- disp_screen_buffer_rows = 0;
- }
-}
-
-void DisplayAllocScreenBuffer()
-{
- if (!disp_screen_buffer_cols) {
- disp_screen_buffer_rows = Settings.display_rows;
- disp_screen_buffer = (char**)malloc(sizeof(*disp_screen_buffer) * disp_screen_buffer_rows);
- if (disp_screen_buffer != NULL) {
- for (byte i = 0; i < disp_screen_buffer_rows; i++) {
- disp_screen_buffer[i] = (char*)malloc(sizeof(*disp_screen_buffer[i]) * (Settings.display_cols[0] +1));
- if (disp_screen_buffer[i] == NULL) {
- DisplayFreeScreenBuffer();
- break;
- }
- }
- }
- if (disp_screen_buffer != NULL) {
- disp_screen_buffer_cols = Settings.display_cols[0] +1;
- DisplayClearScreenBuffer();
- }
- }
-}
-
-void DisplayReAllocScreenBuffer()
-{
- DisplayFreeScreenBuffer();
- DisplayAllocScreenBuffer();
-}
-
-/*-------------------------------------------------------------------------------------------*/
-
-void DisplayClearLogBuffer()
-{
- if (disp_log_buffer_cols) {
- for (byte i = 0; i < DISPLAY_LOG_ROWS; i++) {
- memset(disp_log_buffer[i], 0, disp_log_buffer_cols);
- }
- }
-}
-
-void DisplayFreeLogBuffer()
-{
- if (disp_log_buffer != NULL) {
- for (byte i = 0; i < DISPLAY_LOG_ROWS; i++) {
- if (disp_log_buffer[i] != NULL) { free(disp_log_buffer[i]); }
- }
- free(disp_log_buffer);
- disp_log_buffer_cols = 0;
- }
-}
-
-void DisplayAllocLogBuffer()
-{
- if (!disp_log_buffer_cols) {
- disp_log_buffer = (char**)malloc(sizeof(*disp_log_buffer) * DISPLAY_LOG_ROWS);
- if (disp_log_buffer != NULL) {
- for (byte i = 0; i < DISPLAY_LOG_ROWS; i++) {
- disp_log_buffer[i] = (char*)malloc(sizeof(*disp_log_buffer[i]) * (Settings.display_cols[0] +1));
- if (disp_log_buffer[i] == NULL) {
- DisplayFreeLogBuffer();
- break;
- }
- }
- }
- if (disp_log_buffer != NULL) {
- disp_log_buffer_cols = Settings.display_cols[0] +1;
- DisplayClearLogBuffer();
- }
- }
-}
-
-void DisplayReAllocLogBuffer()
-{
- DisplayFreeLogBuffer();
- DisplayAllocLogBuffer();
-}
-
-/*-------------------------------------------------------------------------------------------*/
-
-void DisplayLogBufferIdxInc()
-{
- disp_log_buffer_idx++;
- if (DISPLAY_LOG_ROWS == disp_log_buffer_idx) {
- disp_log_buffer_idx = 0;
- }
-}
-
-void DisplayLogBufferPtrInc()
-{
- disp_log_buffer_ptr++;
- if (DISPLAY_LOG_ROWS == disp_log_buffer_ptr) {
- disp_log_buffer_ptr = 0;
- }
-}
-
-/*
-void DisplayPrintLog()
-{
- 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) {
- XdspPrintLog(disp_log_buffer[disp_log_buffer_ptr]);
- DisplayLogBufferPtrInc();
- }
- }
-}
-*/
-
-void DisplayLogBufferInit()
-{
- if (Settings.display_mode) {
- disp_log_buffer_idx = 0;
- disp_log_buffer_ptr = 0;
- disp_log_buffer_active = false;
- disp_refresh = Settings.display_refresh;
-
- snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%c"), TempUnit());
-
-// DisplayReAllocLogBuffer();
-
- snprintf_P(disp_log_buffer[disp_log_buffer_idx], disp_log_buffer_cols, PSTR(D_VERSION " %s"), my_version);
- DisplayLogBufferIdxInc();
- snprintf_P(disp_log_buffer[disp_log_buffer_idx], disp_log_buffer_cols, PSTR("Display mode %d"), Settings.display_mode);
- DisplayLogBufferIdxInc();
- }
-}
-
-/*********************************************************************************************\
- * Sensors
-\*********************************************************************************************/
-
-enum SensorQuantity {
- JSON_TEMPERATURE,
- JSON_HUMIDITY, JSON_LIGHT, JSON_NOISE, JSON_AIRQUALITY,
- JSON_PRESSURE, JSON_PRESSUREATSEALEVEL,
- JSON_ILLUMINANCE,
- JSON_GAS,
- JSON_YESTERDAY, JSON_TOTAL, JSON_TODAY,
- JSON_PERIOD,
- JSON_POWERFACTOR, JSON_COUNTER, JSON_ANALOG_INPUT, JSON_UV_LEVEL,
- JSON_CURRENT,
- JSON_VOLTAGE,
- JSON_POWERUSAGE,
- JSON_CO2 };
-const char kSensorQuantity[] PROGMEM =
- D_JSON_TEMPERATURE "|" // degrees
- D_JSON_HUMIDITY "|" D_JSON_LIGHT "|" D_JSON_NOISE "|" D_JSON_AIRQUALITY "|" // percentage
- D_JSON_PRESSURE "|" D_JSON_PRESSUREATSEALEVEL "|" // hPa
- D_JSON_ILLUMINANCE "|" // lx
- D_JSON_GAS "|" // kOhm
- D_JSON_YESTERDAY "|" D_JSON_TOTAL "|" D_JSON_TODAY "|" // kWh
- D_JSON_PERIOD "|" // Wh
- D_JSON_POWERFACTOR "|" D_JSON_COUNTER "|" D_JSON_ANALOG_INPUT "|" D_JSON_UV_LEVEL "|" // No unit
- D_JSON_CURRENT "|" // Ampere
- D_JSON_VOLTAGE "|" // Volt
- D_JSON_POWERUSAGE "|" // Watt
- D_JSON_CO2 ; // ppm
-
-void DisplayJsonValue(const char *topic, const char* device, const char* mkey, const char* value)
-{
- char quantity[TOPSZ];
- char spaces[Settings.display_cols[0]];
- char source[Settings.display_cols[0] - Settings.display_cols[1]];
- char svalue[Settings.display_cols[1] +1];
-
- ShowFreeMem(PSTR("DisplayJsonValue"));
-
- memset(spaces, 0x20, sizeof(spaces));
- spaces[sizeof(spaces) -1] = '\0';
- snprintf_P(source, sizeof(source), PSTR("%s/%s%s"), topic, mkey, spaces); // pow1/Voltage
-
- int quantity_code = GetCommandCode(quantity, sizeof(quantity), mkey, kSensorQuantity);
- if ((-1 == quantity_code) || !strcmp_P(mkey, S_RSLT_POWER)) { // Ok: Power, Not ok: POWER
- return;
- }
- if (JSON_TEMPERATURE == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s~%s"), value, disp_temp);
- }
- else if ((quantity_code >= JSON_HUMIDITY) && (quantity_code <= JSON_AIRQUALITY)) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s%%"), value);
- }
- else if ((quantity_code >= JSON_PRESSURE) && (quantity_code <= JSON_PRESSUREATSEALEVEL)) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_PRESSURE), value);
- }
- else if (JSON_ILLUMINANCE == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_LUX), value);
- }
- else if (JSON_GAS == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_KILOOHM), value);
- }
- else if ((quantity_code >= JSON_YESTERDAY) && (quantity_code <= JSON_TODAY)) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_KILOWATTHOUR), value);
- }
- else if (JSON_PERIOD == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_WATTHOUR), value);
- }
- else if ((quantity_code >= JSON_POWERFACTOR) && (quantity_code <= JSON_UV_LEVEL)) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s"), value);
- }
- else if (JSON_CURRENT == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_AMPERE), value);
- }
- else if (JSON_VOLTAGE == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_VOLT), value);
- }
- else if (JSON_POWERUSAGE == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_WATT), value);
- }
- else if (JSON_CO2 == quantity_code) {
- snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_PARTS_PER_MILLION), value);
- }
- snprintf_P(disp_log_buffer[disp_log_buffer_idx], disp_log_buffer_cols, PSTR("%s %s"), source, svalue);
-
-// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "mkey [%s], source [%s], value [%s], quantity_code %d, log_buffer [%s]"), mkey, source, value, quantity_code, disp_log_buffer[disp_log_buffer_idx]);
-// AddLog(LOG_LEVEL_DEBUG);
-
- DisplayLogBufferIdxInc();
-}
-
-void DisplayAnalyzeJson(char *topic, char *json)
-{
-// //tele/pow2/STATE {"Time":"2017-09-20T11:53:03", "Uptime":10, "Vcc":3.123, "POWER":"ON", "Wifi":{"AP":2, "SSId":"indebuurt2", "RSSI":68, "APMac":"00:22:6B:FE:8E:20"}}
-// //tele/pow2/ENERGY {"Time":"2017-09-20T11:53:03", "Total":6.522, "Yesterday":0.150, "Today":0.073, "Period":0.5, "Power":12.1, "Factor":0.56, "Voltage":210.1, "Current":0.102}
-
-// tele/pow1/SENSOR = {"Time":"2018-01-02T17:13:17","ENERGY":{"Total":13.091,"Yesterday":0.060,"Today":0.046,"Period":0.2,"Power":9.8,"Factor":0.49,"Voltage":206.8,"Current":0.096}}
-// tele/dual/STATE {"Time":"2017-09-20T11:53:03","Uptime":25,"Vcc":3.178,"POWER1":"OFF","POWER2":"OFF","Wifi":{"AP":2,"SSId":"indebuurt2","RSSI":100,"APMac":"00:22:6B:FE:8E:20"}}
-// tele/sc/SENSOR {"Time":"2017-09-20T11:53:09","Temperature":24.0,"Humidity":16.0,"Light":30,"Noise":20,"AirQuality":100,"TempUnit":"C"}
-// tele/rf1/SENSOR {"Time":"2017-09-20T11:53:23","BH1750":{"Illuminance":57}}
-// tele/wemos5/SENSOR {"Time":"2017-09-20T11:53:53","SHT1X":{"Temperature":20.1,"Humidity":58.9},"HTU21":{"Temperature":20.7,"Humidity":58.5},"BMP280":{"Temperature":21.6,"Pressure":1020.3},"TempUnit":"C"}
-// tele/th1/SENSOR {"Time":"2017-09-20T11:54:48","DS18B20":{"Temperature":49.7},"TempUnit":"C"}
-
- const char *tempunit;
-
-// char jsonStr[MESSZ];
-// strlcpy(jsonStr, json, sizeof(jsonStr)); // Save original before destruction by JsonObject
- String jsonStr = json; // Move from stack to heap to fix watchdogs (20180626)
-
- StaticJsonBuffer<1024> jsonBuf;
- JsonObject &root = jsonBuf.parseObject(jsonStr);
- if (root.success()) {
-
- tempunit = root[D_JSON_TEMPERATURE_UNIT];
- if (tempunit) {
- snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%s"), tempunit);
-// snprintf_P(log_data, sizeof(log_data), disp_temp);
-// AddLog(LOG_LEVEL_DEBUG);
- }
-
- for (JsonObject::iterator it = root.begin(); it != root.end(); ++it) {
- JsonVariant value = it->value;
- if (value.is()) {
- JsonObject& Object2 = value;
- for (JsonObject::iterator it2 = Object2.begin(); it2 != Object2.end(); ++it2) {
- JsonVariant value2 = it2->value;
- if (value2.is()) {
- JsonObject& Object3 = value2;
- for (JsonObject::iterator it3 = Object3.begin(); it3 != Object3.end(); ++it3) {
- DisplayJsonValue(topic, it->key, it3->key, it3->value.as()); // Sensor 56%
- }
- } else {
- DisplayJsonValue(topic, it->key, it2->key, it2->value.as()); // Sensor 56%
- }
- }
- } else {
- DisplayJsonValue(topic, it->key, it->key, it->value.as()); // Topic 56%
- }
- }
- }
-}
-
-void DisplayMqttSubscribe()
-{
-/* Subscribe to tele messages only
- * Supports the following FullTopic formats
- * - %prefix%/%topic%
- * - home/%prefix%/%topic%
- * - home/level2/%prefix%/%topic% etc.
- */
-// if (Settings.display_mode &0x04) {
- if (Settings.display_model) {
-
- char stopic[TOPSZ];
- char ntopic[TOPSZ];
-
- ntopic[0] = '\0';
- strlcpy(stopic, Settings.mqtt_fulltopic, sizeof(stopic));
- char *tp = strtok(stopic, "/");
- while (tp != NULL) {
- if (!strcmp_P(tp, PSTR(MQTT_TOKEN_PREFIX))) {
- break;
- }
- strncat_P(ntopic, PSTR("+/"), sizeof(ntopic)); // Add single-level wildcards
- tp = strtok(NULL, "/");
- }
- strncat(ntopic, Settings.mqtt_prefix[2], sizeof(ntopic)); // Subscribe to tele messages
- strncat_P(ntopic, PSTR("/#"), sizeof(ntopic)); // Add multi-level wildcard
- MqttSubscribe(ntopic);
- disp_subscribed = 1;
- } else {
- disp_subscribed = 0;
- }
-}
-
-boolean DisplayMqttData()
-{
- if (disp_subscribed) {
- char stopic[TOPSZ];
-
- snprintf_P(stopic, sizeof(stopic) , PSTR("%s/"), Settings.mqtt_prefix[2]); // tele/
- char *tp = strstr(XdrvMailbox.topic, stopic);
- if (tp) { // tele/sonoff/SENSOR
- if (Settings.display_mode &0x04) {
- tp = tp + strlen(stopic); // sonoff/SENSOR
- char *topic = strtok(tp, "/"); // sonoff
- DisplayAnalyzeJson(topic, XdrvMailbox.data);
- }
- return true;
- }
- }
- return false;
-}
-
-void DisplayLocalSensor()
-{
- if ((Settings.display_mode &0x02) && (0 == tele_period)) {
- DisplayAnalyzeJson(mqtt_topic, mqtt_data);
- }
-}
-
-#endif // USE_DISPLAY_MODES1TO5
-
-/*********************************************************************************************\
- * Public
-\*********************************************************************************************/
-
-void DisplayInitDriver()
-{
- XdspCall(FUNC_DISPLAY_INIT_DRIVER);
-
-// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model);
-// AddLog(LOG_LEVEL_DEBUG);
-
- if (Settings.display_model) {
- devices_present++;
- disp_device = devices_present;
-
-#ifndef USE_DISPLAY_MODES1TO5
- Settings.display_mode = 0;
-#else
- DisplayAllocLogBuffer();
- DisplayLogBufferInit();
-#endif // USE_DISPLAY_MODES1TO5
- }
-}
-
-void DisplaySetPower()
-{
- disp_power = bitRead(XdrvMailbox.index, disp_device -1);
- if (Settings.display_model) {
- XdspCall(FUNC_DISPLAY_POWER);
- }
-}
-
-/*********************************************************************************************\
- * Commands
-\*********************************************************************************************/
-
-boolean DisplayCommand()
-{
- char command [CMDSZ];
- boolean serviced = true;
- uint8_t disp_len = strlen(D_CMND_DISPLAY); // Prep for string length change
-
- if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_DISPLAY), disp_len)) { // Prefix
- int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic +disp_len, kDisplayCommands);
- if (-1 == command_code) {
- serviced = false; // Unknown command
- }
- else if (CMND_DISP_MODEL == command_code) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < DISPLAY_MAX_DRIVERS)) {
- uint8_t last_display_model = Settings.display_model;
- Settings.display_model = XdrvMailbox.payload;
- if (XdspCall(FUNC_DISPLAY_MODEL)) {
- restart_flag = 2; // Restart to re-init interface and add/Remove MQTT subscribe
- } else {
- Settings.display_model = last_display_model;
- }
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_model);
- }
- else if (CMND_DISP_MODE == command_code) {
-#ifdef USE_DISPLAY_MODES1TO5
-/* Matrix LCD / Oled TFT
- * 1 = Text up and time Time
- * 2 = Date Local sensors Local sensors
- * 3 = Day Local sensors and time Local sensors and time
- * 4 = Mqtt left and time Mqtt (incl local) sensors Mqtt (incl local) sensors
- * 5 = Mqtt up and time Mqtt (incl local) sensors and time Mqtt (incl local) sensors and time
-*/
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 5)) {
- uint8_t last_display_mode = Settings.display_mode;
- Settings.display_mode = XdrvMailbox.payload;
- if (!disp_subscribed) {
- restart_flag = 2; // Restart to Add/Remove MQTT subscribe
- } else {
- if (last_display_mode && !Settings.display_mode) { // Switch to mode 0
- DisplayInit(DISPLAY_INIT_MODE);
- DisplayClear();
- }
- if (!last_display_mode && Settings.display_mode) { // Switch to non mode 0
- DisplayLogBufferInit();
- DisplayInit(DISPLAY_INIT_MODE);
- }
- }
- }
-#endif // USE_DISPLAY_MODES1TO5
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_mode);
- }
- else if (CMND_DISP_DIMMER == command_code) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
- Settings.display_dimmer = ((XdrvMailbox.payload +1) * 100) / 666; // Correction for Domoticz (0 - 15)
- if (Settings.display_dimmer && !(disp_power)) {
- ExecuteCommandPower(disp_device, POWER_ON, SRC_DISPLAY);
- }
- else if (!Settings.display_dimmer && disp_power) {
- ExecuteCommandPower(disp_device, POWER_OFF, SRC_DISPLAY);
- }
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_dimmer);
- }
- else if (CMND_DISP_SIZE == command_code) {
- if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
- Settings.display_size = XdrvMailbox.payload;
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_size);
- }
- else if (CMND_DISP_FONT == command_code) {
- if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
- Settings.display_font = XdrvMailbox.payload;
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_font);
- }
- else if (CMND_DISP_ROTATE == command_code) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 4)) {
- if (Settings.display_rotate != XdrvMailbox.payload) {
-/*
- // Needs font info regarding height and width
- if ((Settings.display_rotate &1) != (XdrvMailbox.payload &1)) {
- uint8_t temp_rows = Settings.display_rows;
- Settings.display_rows = Settings.display_cols[0];
- Settings.display_cols[0] = temp_rows;
-#ifdef USE_DISPLAY_MODES1TO5
- DisplayReAllocScreenBuffer();
-#endif // USE_DISPLAY_MODES1TO5
- }
-*/
- Settings.display_rotate = XdrvMailbox.payload;
- DisplayInit(DISPLAY_INIT_MODE);
-#ifdef USE_DISPLAY_MODES1TO5
- DisplayLogBufferInit();
-#endif // USE_DISPLAY_MODES1TO5
- }
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rotate);
- }
- else if (CMND_DISP_TEXT == command_code) {
- mqtt_data[0] = '\0';
- if (disp_device && XdrvMailbox.data_len > 0) {
-#ifndef USE_DISPLAY_MODES1TO5
- DisplayText();
-#else
- if (!Settings.display_mode) {
- DisplayText();
- } else {
- strlcpy(disp_log_buffer[disp_log_buffer_idx], XdrvMailbox.data, disp_log_buffer_cols);
- DisplayLogBufferIdxInc();
- }
-#endif // USE_DISPLAY_MODES1TO5
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("No Text"));
- }
- if (mqtt_data[0] == '\0') {
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_VALUE, command, XdrvMailbox.data);
- }
- }
- else if ((CMND_DISP_ADDRESS == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
- Settings.display_address[XdrvMailbox.index -1] = XdrvMailbox.payload;
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_address[XdrvMailbox.index -1]);
- }
- else if (CMND_DISP_REFRESH == command_code) {
- if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) {
- Settings.display_refresh = XdrvMailbox.payload;
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_refresh);
- }
- else if ((CMND_DISP_COLS == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
- if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_COLS)) {
-#ifdef USE_DISPLAY_MODES1TO5
- if ((1 == XdrvMailbox.index) && (Settings.display_cols[0] != XdrvMailbox.payload)) {
- DisplayLogBufferInit();
- DisplayReAllocScreenBuffer();
- }
-#endif // USE_DISPLAY_MODES1TO5
- Settings.display_cols[XdrvMailbox.index -1] = XdrvMailbox.payload;
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_cols[XdrvMailbox.index -1]);
- }
- else if (CMND_DISP_ROWS == command_code) {
- if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_ROWS)) {
-#ifdef USE_DISPLAY_MODES1TO5
- if (Settings.display_rows != XdrvMailbox.payload) { DisplayReAllocScreenBuffer(); }
-#endif // USE_DISPLAY_MODES1TO5
- Settings.display_rows = XdrvMailbox.payload;
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rows);
- }
- else serviced = false; // Unknown command
- }
- else serviced = false; // Unknown command
-
- return serviced;
-}
-
-/*********************************************************************************************\
- * Interface
-\*********************************************************************************************/
-
-#define XDRV_13
-
-boolean Xdrv13(byte function)
-{
- boolean result = false;
-
- if ((i2c_flg || spi_flg) && XdspPresent()) {
- switch (function) {
- case FUNC_PRE_INIT:
- DisplayInitDriver();
- break;
- case FUNC_EVERY_50_MSECOND:
- if (Settings.display_model) { XdspCall(FUNC_DISPLAY_EVERY_50_MSECOND); }
- break;
- case FUNC_COMMAND:
- result = DisplayCommand();
- break;
- case FUNC_SET_POWER:
- DisplaySetPower();
- break;
-#ifdef USE_DISPLAY_MODES1TO5
- case FUNC_EVERY_SECOND:
- if (Settings.display_model && Settings.display_mode) { XdspCall(FUNC_DISPLAY_EVERY_SECOND); }
- break;
- case FUNC_MQTT_SUBSCRIBE:
- DisplayMqttSubscribe();
- break;
- case FUNC_MQTT_DATA:
- result = DisplayMqttData();
- break;
- case FUNC_SHOW_SENSOR:
- DisplayLocalSensor();
- break;
-#endif // USE_DISPLAY_MODES1TO5
- }
- }
- return result;
-}
-
-#endif // USE_DISPLAY
-#endif // USE_I2C or USE_SPI
diff --git a/sonoff/xdrv_99_debug.ino b/sonoff/xdrv_99_debug.ino
deleted file mode 100644
index 8a167511c..000000000
--- a/sonoff/xdrv_99_debug.ino
+++ /dev/null
@@ -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 .
-*/
-
-//#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
- 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
- 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
\ No newline at end of file
diff --git a/sonoff/xdsp_01_lcd.ino b/sonoff/xdsp_01_lcd.ino
deleted file mode 100644
index 37f4c9bcc..000000000
--- a/sonoff/xdsp_01_lcd.ino
+++ /dev/null
@@ -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 .
-*/
-
-#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
-#include
-
-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
diff --git a/sonoff/xdsp_02_ssd1306.ino b/sonoff/xdsp_02_ssd1306.ino
deleted file mode 100644
index 704daf92b..000000000
--- a/sonoff/xdsp_02_ssd1306.ino
+++ /dev/null
@@ -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 .
-*/
-
-#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
-#include
-#include
-
-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
diff --git a/sonoff/xdsp_03_matrix.ino b/sonoff/xdsp_03_matrix.ino
deleted file mode 100644
index 868a2c9bd..000000000
--- a/sonoff/xdsp_03_matrix.ino
+++ /dev/null
@@ -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 .
-*/
-
-#ifdef USE_I2C
-#ifdef USE_DISPLAY
-#ifdef USE_DISPLAY_MATRIX
-
-#define XDSP_03 3
-
-#define MTX_MAX_SCREEN_BUFFER 80
-
-#include
-#include
-#include // 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
diff --git a/sonoff/xdsp_04_ili9341.ino b/sonoff/xdsp_04_ili9341.ino
deleted file mode 100644
index 34f3682da..000000000
--- a/sonoff/xdsp_04_ili9341.ino
+++ /dev/null
@@ -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 .
-*/
-
-#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
-#include
-#include // 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
diff --git a/sonoff/xdsp_05_epaper.ino b/sonoff/xdsp_05_epaper.ino
deleted file mode 100644
index 59a08584b..000000000
--- a/sonoff/xdsp_05_epaper.ino
+++ /dev/null
@@ -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 .
-*/
-
-#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
-#include
-
-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
diff --git a/sonoff/xdsp_interface.ino b/sonoff/xdsp_interface.ino
deleted file mode 100644
index 8d6d5a814..000000000
--- a/sonoff/xdsp_interface.ino
+++ /dev/null
@@ -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 .
-*/
-
-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;
-}
diff --git a/sonoff/xsns_27_apds9960.ino b/sonoff/xsns_27_apds9960.ino
deleted file mode 100644
index 151d9b732..000000000
--- a/sonoff/xsns_27_apds9960.ino
+++ /dev/null
@@ -1,2123 +0,0 @@
-/*
- xsns_27_apds9960.ino - Support for I2C APDS9960 Proximity Sensor for Sonoff-Tasmota
-
- Copyright (C) 2018 Shawn Hymel/Sparkfun and Theo Arends
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- - Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifdef USE_I2C
-#ifdef USE_APDS9960
-
-#define XSNS_27 27
-
-/*********************************************************************************************\
- * APDS9960 - Digital Proximity Ambient Light RGB and Gesture Sensor
- *
- * Source: Shawn Hymel (SparkFun Electronics)
- * Adaption for TASMOTA: Christian Baars
- *
- * I2C Address: 0x39
-\*********************************************************************************************/
-
-#if defined(USE_SHT) || defined(USE_VEML6070)
- #warning **** Turned off conflicting drivers SHT and VEML6070 ****
- #ifdef USE_SHT
- #undef USE_SHT // SHT-Driver blocks gesture sensor
- #endif
- #ifdef USE_VEML6070
- #undef USE_VEML6070 // address conflict on the I2C-bus
- #endif
-#endif
-
-#define APDS9960_I2C_ADDR 0x39
-
-#define APDS9960_CHIPID_1 0xAB
-#define APDS9960_CHIPID_2 0x9C
-
-/* Gesture parameters */
-#define GESTURE_THRESHOLD_OUT 10
-#define GESTURE_SENSITIVITY_1 50
-#define GESTURE_SENSITIVITY_2 20
-
-uint8_t APDS9960addr;
-uint8_t APDS9960type = 0;
-char APDS9960stype[7];
-char currentGesture[6];
-uint8_t gesture_mode = 1;
-
-volatile uint8_t recovery_loop_counter = 0; //count number of stateloops to switch the sensor off, if needed
-#define APDS9960_LONG_RECOVERY 50 //long pause after sensor overload in loops
-#define APDS9960_MAX_GESTURE_CYCLES 50 //how many FIFO-reads are allowed to prevent crash
-bool APDS9960_overload = false;
-
-#ifdef USE_WEBSERVER
-const char HTTP_APDS_9960_SNS[] PROGMEM = "%s"
- "{s}" "Red" "{m}%s{e}"
- "{s}" "Green" "{m}%s{e}"
- "{s}" "Blue" "{m}%s{e}"
- "{s}" "Ambient" "{m}%s " D_UNIT_LUX "{e}"
- "{s}" "Proximity" "{m}%s{e}"; // {s} = , {m} = | , {e} = |
-#endif // USE_WEBSERVER
-
-/*********************************************************************************************\
- * APDS9960
- *
- * Programmer : APDS9960 Datasheet and Sparkfun
-\*********************************************************************************************/
-
-/* Misc parameters */
-#define FIFO_PAUSE_TIME 30 // Wait period (ms) between FIFO reads
-
-/* APDS-9960 register addresses */
-#define APDS9960_ENABLE 0x80
-#define APDS9960_ATIME 0x81
-#define APDS9960_WTIME 0x83
-#define APDS9960_AILTL 0x84
-#define APDS9960_AILTH 0x85
-#define APDS9960_AIHTL 0x86
-#define APDS9960_AIHTH 0x87
-#define APDS9960_PILT 0x89
-#define APDS9960_PIHT 0x8B
-#define APDS9960_PERS 0x8C
-#define APDS9960_CONFIG1 0x8D
-#define APDS9960_PPULSE 0x8E
-#define APDS9960_CONTROL 0x8F
-#define APDS9960_CONFIG2 0x90
-#define APDS9960_ID 0x92
-#define APDS9960_STATUS 0x93
-#define APDS9960_CDATAL 0x94
-#define APDS9960_CDATAH 0x95
-#define APDS9960_RDATAL 0x96
-#define APDS9960_RDATAH 0x97
-#define APDS9960_GDATAL 0x98
-#define APDS9960_GDATAH 0x99
-#define APDS9960_BDATAL 0x9A
-#define APDS9960_BDATAH 0x9B
-#define APDS9960_PDATA 0x9C
-#define APDS9960_POFFSET_UR 0x9D
-#define APDS9960_POFFSET_DL 0x9E
-#define APDS9960_CONFIG3 0x9F
-#define APDS9960_GPENTH 0xA0
-#define APDS9960_GEXTH 0xA1
-#define APDS9960_GCONF1 0xA2
-#define APDS9960_GCONF2 0xA3
-#define APDS9960_GOFFSET_U 0xA4
-#define APDS9960_GOFFSET_D 0xA5
-#define APDS9960_GOFFSET_L 0xA7
-#define APDS9960_GOFFSET_R 0xA9
-#define APDS9960_GPULSE 0xA6
-#define APDS9960_GCONF3 0xAA
-#define APDS9960_GCONF4 0xAB
-#define APDS9960_GFLVL 0xAE
-#define APDS9960_GSTATUS 0xAF
-#define APDS9960_IFORCE 0xE4
-#define APDS9960_PICLEAR 0xE5
-#define APDS9960_CICLEAR 0xE6
-#define APDS9960_AICLEAR 0xE7
-#define APDS9960_GFIFO_U 0xFC
-#define APDS9960_GFIFO_D 0xFD
-#define APDS9960_GFIFO_L 0xFE
-#define APDS9960_GFIFO_R 0xFF
-
-/* Bit fields */
-#define APDS9960_PON 0b00000001
-#define APDS9960_AEN 0b00000010
-#define APDS9960_PEN 0b00000100
-#define APDS9960_WEN 0b00001000
-#define APSD9960_AIEN 0b00010000
-#define APDS9960_PIEN 0b00100000
-#define APDS9960_GEN 0b01000000
-#define APDS9960_GVALID 0b00000001
-
-/* On/Off definitions */
-#define OFF 0
-#define ON 1
-
-/* Acceptable parameters for setMode */
-#define POWER 0
-#define AMBIENT_LIGHT 1
-#define PROXIMITY 2
-#define WAIT 3
-#define AMBIENT_LIGHT_INT 4
-#define PROXIMITY_INT 5
-#define GESTURE 6
-#define ALL 7
-
-/* LED Drive values */
-#define LED_DRIVE_100MA 0
-#define LED_DRIVE_50MA 1
-#define LED_DRIVE_25MA 2
-#define LED_DRIVE_12_5MA 3
-
-/* Proximity Gain (PGAIN) values */
-#define PGAIN_1X 0
-#define PGAIN_2X 1
-#define PGAIN_4X 2
-#define PGAIN_8X 3
-
-/* ALS Gain (AGAIN) values */
-#define AGAIN_1X 0
-#define AGAIN_4X 1
-#define AGAIN_16X 2
-#define AGAIN_64X 3
-
-/* Gesture Gain (GGAIN) values */
-#define GGAIN_1X 0
-#define GGAIN_2X 1
-#define GGAIN_4X 2
-#define GGAIN_8X 3
-
-/* LED Boost values */
-#define LED_BOOST_100 0
-#define LED_BOOST_150 1
-#define LED_BOOST_200 2
-#define LED_BOOST_300 3
-
-/* Gesture wait time values */
-#define GWTIME_0MS 0
-#define GWTIME_2_8MS 1
-#define GWTIME_5_6MS 2
-#define GWTIME_8_4MS 3
-#define GWTIME_14_0MS 4
-#define GWTIME_22_4MS 5
-#define GWTIME_30_8MS 6
-#define GWTIME_39_2MS 7
-
-/* Default values */
-#define DEFAULT_ATIME 219 // 103ms
-#define DEFAULT_WTIME 246 // 27ms
-#define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses
-#define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses
-#define DEFAULT_POFFSET_UR 0 // 0 offset
-#define DEFAULT_POFFSET_DL 0 // 0 offset
-#define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor
-#define DEFAULT_LDRIVE LED_DRIVE_100MA
-#define DEFAULT_PGAIN PGAIN_4X
-#define DEFAULT_AGAIN AGAIN_4X
-#define DEFAULT_PILT 0 // Low proximity threshold
-#define DEFAULT_PIHT 50 // High proximity threshold
-#define DEFAULT_AILT 0xFFFF // Force interrupt for calibration
-#define DEFAULT_AIHT 0
-#define DEFAULT_PERS 0x11 // 2 consecutive prox or ALS for int.
-#define DEFAULT_CONFIG2 0x01 // No saturation interrupts or LED boost
-#define DEFAULT_CONFIG3 0 // Enable all photodiodes, no SAI
-#define DEFAULT_GPENTH 40 // Threshold for entering gesture mode
-#define DEFAULT_GEXTH 30 // Threshold for exiting gesture mode
-#define DEFAULT_GCONF1 0x40 // 4 gesture events for int., 1 for exit
-#define DEFAULT_GGAIN GGAIN_4X
-#define DEFAULT_GLDRIVE LED_DRIVE_100MA
-#define DEFAULT_GWTIME GWTIME_2_8MS
-#define DEFAULT_GOFFSET 0 // No offset scaling for gesture mode
-#define DEFAULT_GPULSE 0xC9 // 32us, 10 pulses
-#define DEFAULT_GCONF3 0 // All photodiodes active during gesture
-#define DEFAULT_GIEN 0 // Disable gesture interrupts
-
-#define ERROR 0xFF
-
-/* Direction definitions */
-enum {
- DIR_NONE,
- DIR_LEFT,
- DIR_RIGHT,
- DIR_UP,
- DIR_DOWN,
- DIR_ALL
-};
-
-/* State definitions*/
-enum {
- APDS9960_NA_STATE,
- APDS9960_ALL_STATE
-};
-
-/* Container for gesture data */
-typedef struct gesture_data_type {
- uint8_t u_data[32];
- uint8_t d_data[32];
- uint8_t l_data[32];
- uint8_t r_data[32];
- uint8_t index;
- uint8_t total_gestures;
- uint8_t in_threshold;
- uint8_t out_threshold;
-} gesture_data_type;
-
-/*Members*/
- gesture_data_type gesture_data_;
- int16_t gesture_ud_delta_ = 0;
- int16_t gesture_lr_delta_ = 0;
- int16_t gesture_ud_count_ = 0;
- int16_t gesture_lr_count_ = 0;
- int16_t gesture_state_ = 0;
- int16_t gesture_motion_ = DIR_NONE;
-
- /*******************************************************************************
- * Helper functions
- ******************************************************************************/
-
- /**
- * @brief Writes a single byte to the I2C device (no register)
- *
- * @param[in] val the 1-byte value to write to the I2C device
- * @return True if successful write operation. False otherwise.
- */
- bool wireWriteByte(uint8_t val)
- {
- Wire.beginTransmission(APDS9960_I2C_ADDR);
- Wire.write(val);
- if( Wire.endTransmission() != 0 ) {
- return false;
- }
-
- return true;
- }
- /**
- * @brief Reads a block (array) of bytes from the I2C device and register
- *
- * @param[in] reg the register to read from
- * @param[out] val pointer to the beginning of the data
- * @param[in] len number of bytes to read
- * @return Number of bytes read. -1 on read error.
- */
-int8_t wireReadDataBlock( uint8_t reg,
- uint8_t *val,
- uint16_t len)
-{
- unsigned char i = 0;
-
- /* Indicate which register we want to read from */
- if (!wireWriteByte(reg)) {
- return -1;
- }
-
- /* Read block data */
- Wire.requestFrom(APDS9960_I2C_ADDR, len);
- while (Wire.available()) {
- if (i >= len) {
- return -1;
- }
- val[i] = Wire.read();
- i++;
- }
-
- return i;
-}
-
- /*******************************************************************************
- * Getters and setters for register values
- ******************************************************************************/
-
- /**
- * @brief Returns the lower threshold for proximity detection
- *
- * @return lower threshold
- */
- uint8_t getProxIntLowThresh()
- {
- uint8_t val;
-
- /* Read value from PILT register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PILT) ;
- return val;
- }
-
- /**
- * @brief Sets the lower threshold for proximity detection
- *
- * @param[in] threshold the lower proximity threshold
- */
- void setProxIntLowThresh(uint8_t threshold)
- {
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PILT, threshold);
- }
-
- /**
- * @brief Returns the high threshold for proximity detection
- *
- * @return high threshold
- */
- uint8_t getProxIntHighThresh()
- {
- uint8_t val;
-
- /* Read value from PIHT register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PIHT) ;
- return val;
- }
-
- /**
- * @brief Sets the high threshold for proximity detection
- *
- * @param[in] threshold the high proximity threshold
- */
-
- void setProxIntHighThresh(uint8_t threshold)
- {
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PIHT, threshold);
- }
-
-
- /**
- * @brief Returns LED drive strength for proximity and ALS
- *
- * Value LED Current
- * 0 100 mA
- * 1 50 mA
- * 2 25 mA
- * 3 12.5 mA
- *
- * @return the value of the LED drive strength. 0xFF on failure.
- */
- uint8_t getLEDDrive()
- {
- uint8_t val;
-
- /* Read value from CONTROL register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL) ;
- /* Shift and mask out LED drive bits */
- val = (val >> 6) & 0b00000011;
-
- return val;
- }
-
- /**
- * @brief Sets the LED drive strength for proximity and ALS
- *
- * Value LED Current
- * 0 100 mA
- * 1 50 mA
- * 2 25 mA
- * 3 12.5 mA
- *
- * @param[in] drive the value (0-3) for the LED drive strength
- */
- void setLEDDrive(uint8_t drive)
- {
- uint8_t val;
-
- /* Read value from CONTROL register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL);
-
- /* Set bits in register to given value */
- drive &= 0b00000011;
- drive = drive << 6;
- val &= 0b00111111;
- val |= drive;
-
- /* Write register value back into CONTROL register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONTROL, val);
- }
-
-
- /**
- * @brief Returns receiver gain for proximity detection
- *
- * Value Gain
- * 0 1x
- * 1 2x
- * 2 4x
- * 3 8x
- *
- * @return the value of the proximity gain. 0xFF on failure.
- */
- uint8_t getProximityGain()
- {
- uint8_t val;
-
- /* Read value from CONTROL register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL) ;
- /* Shift and mask out PDRIVE bits */
- val = (val >> 2) & 0b00000011;
-
- return val;
- }
-
- /**
- * @brief Sets the receiver gain for proximity detection
- *
- * Value Gain
- * 0 1x
- * 1 2x
- * 2 4x
- * 3 8x
- *
- * @param[in] drive the value (0-3) for the gain
- */
- void setProximityGain(uint8_t drive)
- {
- uint8_t val;
-
- /* Read value from CONTROL register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL);
-
- /* Set bits in register to given value */
- drive &= 0b00000011;
- drive = drive << 2;
- val &= 0b11110011;
- val |= drive;
-
- /* Write register value back into CONTROL register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONTROL, val);
- }
-
-
- /**
- * @brief Returns receiver gain for the ambient light sensor (ALS)
- *
- * Value Gain
- * 0 1x
- * 1 4x
- * 2 16x
- * 3 64x
- *
- * @return the value of the ALS gain. 0xFF on failure.
- */
-
- /**
- * @brief Sets the receiver gain for the ambient light sensor (ALS)
- *
- * Value Gain
- * 0 1x
- * 1 4x
- * 2 16x
- * 3 64x
- *
- * @param[in] drive the value (0-3) for the gain
- */
- void setAmbientLightGain(uint8_t drive)
- {
- uint8_t val;
-
- /* Read value from CONTROL register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL);
-
- /* Set bits in register to given value */
- drive &= 0b00000011;
- val &= 0b11111100;
- val |= drive;
-
- /* Write register value back into CONTROL register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONTROL, val);
- }
-
- /**
- * @brief Get the current LED boost value
- *
- * Value Boost Current
- * 0 100%
- * 1 150%
- * 2 200%
- * 3 300%
- *
- * @return The LED boost value. 0xFF on failure.
- */
- uint8_t getLEDBoost()
- {
- uint8_t val;
-
- /* Read value from CONFIG2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG2) ;
-
- /* Shift and mask out LED_BOOST bits */
- val = (val >> 4) & 0b00000011;
-
- return val;
- }
-
- /**
- * @brief Sets the LED current boost value
- *
- * Value Boost Current
- * 0 100%
- * 1 150%
- * 2 200%
- * 3 300%
- *
- * @param[in] drive the value (0-3) for current boost (100-300%)
- */
- void setLEDBoost(uint8_t boost)
- {
- uint8_t val;
-
- /* Read value from CONFIG2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG2) ;
- /* Set bits in register to given value */
- boost &= 0b00000011;
- boost = boost << 4;
- val &= 0b11001111;
- val |= boost;
-
- /* Write register value back into CONFIG2 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG2, val) ;
- }
-
- /**
- * @brief Gets proximity gain compensation enable
- *
- * @return 1 if compensation is enabled. 0 if not. 0xFF on error.
- */
- uint8_t getProxGainCompEnable()
- {
- uint8_t val;
-
- /* Read value from CONFIG3 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ;
-
- /* Shift and mask out PCMP bits */
- val = (val >> 5) & 0b00000001;
-
- return val;
- }
-
- /**
- * @brief Sets the proximity gain compensation enable
- *
- * @param[in] enable 1 to enable compensation. 0 to disable compensation.
- */
- void setProxGainCompEnable(uint8_t enable)
- {
- uint8_t val;
-
- /* Read value from CONFIG3 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ;
-
- /* Set bits in register to given value */
- enable &= 0b00000001;
- enable = enable << 5;
- val &= 0b11011111;
- val |= enable;
-
- /* Write register value back into CONFIG3 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG3, val) ;
- }
-
- /**
- * @brief Gets the current mask for enabled/disabled proximity photodiodes
- *
- * 1 = disabled, 0 = enabled
- * Bit Photodiode
- * 3 UP
- * 2 DOWN
- * 1 LEFT
- * 0 RIGHT
- *
- * @return Current proximity mask for photodiodes. 0xFF on error.
- */
- uint8_t getProxPhotoMask()
- {
- uint8_t val;
-
- /* Read value from CONFIG3 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ;
-
- /* Mask out photodiode enable mask bits */
- val &= 0b00001111;
-
- return val;
- }
-
- /**
- * @brief Sets the mask for enabling/disabling proximity photodiodes
- *
- * 1 = disabled, 0 = enabled
- * Bit Photodiode
- * 3 UP
- * 2 DOWN
- * 1 LEFT
- * 0 RIGHT
- *
- * @param[in] mask 4-bit mask value
- */
- void setProxPhotoMask(uint8_t mask)
- {
- uint8_t val;
-
- /* Read value from CONFIG3 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ;
-
- /* Set bits in register to given value */
- mask &= 0b00001111;
- val &= 0b11110000;
- val |= mask;
-
- /* Write register value back into CONFIG3 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG3, val) ;
- }
-
- /**
- * @brief Gets the entry proximity threshold for gesture sensing
- *
- * @return Current entry proximity threshold.
- */
- uint8_t getGestureEnterThresh()
- {
- uint8_t val;
-
- /* Read value from GPENTH register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GPENTH) ;
-
- return val;
- }
-
- /**
- * @brief Sets the entry proximity threshold for gesture sensing
- *
- * @param[in] threshold proximity value needed to start gesture mode
- */
- void setGestureEnterThresh(uint8_t threshold)
- {
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GPENTH, threshold) ;
-
- }
-
- /**
- * @brief Gets the exit proximity threshold for gesture sensing
- *
- * @return Current exit proximity threshold.
- */
- uint8_t getGestureExitThresh()
- {
- uint8_t val;
-
- /* Read value from GEXTH register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GEXTH) ;
-
- return val;
- }
-
- /**
- * @brief Sets the exit proximity threshold for gesture sensing
- *
- * @param[in] threshold proximity value needed to end gesture mode
- */
- void setGestureExitThresh(uint8_t threshold)
- {
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GEXTH, threshold) ;
- }
-
- /**
- * @brief Gets the gain of the photodiode during gesture mode
- *
- * Value Gain
- * 0 1x
- * 1 2x
- * 2 4x
- * 3 8x
- *
- * @return the current photodiode gain. 0xFF on error.
- */
- uint8_t getGestureGain()
- {
- uint8_t val;
-
- /* Read value from GCONF2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ;
-
- /* Shift and mask out GGAIN bits */
- val = (val >> 5) & 0b00000011;
-
- return val;
- }
-
- /**
- * @brief Sets the gain of the photodiode during gesture mode
- *
- * Value Gain
- * 0 1x
- * 1 2x
- * 2 4x
- * 3 8x
- *
- * @param[in] gain the value for the photodiode gain
- */
- void setGestureGain(uint8_t gain)
- {
- uint8_t val;
-
- /* Read value from GCONF2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ;
-
- /* Set bits in register to given value */
- gain &= 0b00000011;
- gain = gain << 5;
- val &= 0b10011111;
- val |= gain;
-
- /* Write register value back into GCONF2 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF2, val) ;
- }
-
- /**
- * @brief Gets the drive current of the LED during gesture mode
- *
- * Value LED Current
- * 0 100 mA
- * 1 50 mA
- * 2 25 mA
- * 3 12.5 mA
- *
- * @return the LED drive current value. 0xFF on error.
- */
- uint8_t getGestureLEDDrive()
- {
- uint8_t val;
-
- /* Read value from GCONF2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ;
-
- /* Shift and mask out GLDRIVE bits */
- val = (val >> 3) & 0b00000011;
-
- return val;
- }
-
- /**
- * @brief Sets the LED drive current during gesture mode
- *
- * Value LED Current
- * 0 100 mA
- * 1 50 mA
- * 2 25 mA
- * 3 12.5 mA
- *
- * @param[in] drive the value for the LED drive current
- */
- void setGestureLEDDrive(uint8_t drive)
- {
- uint8_t val;
-
- /* Read value from GCONF2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ;
-
- /* Set bits in register to given value */
- drive &= 0b00000011;
- drive = drive << 3;
- val &= 0b11100111;
- val |= drive;
-
- /* Write register value back into GCONF2 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF2, val) ;
- }
-
- /**
- * @brief Gets the time in low power mode between gesture detections
- *
- * Value Wait time
- * 0 0 ms
- * 1 2.8 ms
- * 2 5.6 ms
- * 3 8.4 ms
- * 4 14.0 ms
- * 5 22.4 ms
- * 6 30.8 ms
- * 7 39.2 ms
- *
- * @return the current wait time between gestures. 0xFF on error.
- */
- uint8_t getGestureWaitTime()
- {
- uint8_t val;
-
- /* Read value from GCONF2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ;
-
- /* Mask out GWTIME bits */
- val &= 0b00000111;
-
- return val;
- }
-
- /**
- * @brief Sets the time in low power mode between gesture detections
- *
- * Value Wait time
- * 0 0 ms
- * 1 2.8 ms
- * 2 5.6 ms
- * 3 8.4 ms
- * 4 14.0 ms
- * 5 22.4 ms
- * 6 30.8 ms
- * 7 39.2 ms
- *
- * @param[in] the value for the wait time
- */
- void setGestureWaitTime(uint8_t time)
- {
- uint8_t val;
-
- /* Read value from GCONF2 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ;
-
- /* Set bits in register to given value */
- time &= 0b00000111;
- val &= 0b11111000;
- val |= time;
-
- /* Write register value back into GCONF2 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF2, val) ;
- }
-
- /**
- * @brief Gets the low threshold for ambient light interrupts
- *
- * @param[out] threshold current low threshold stored on the APDS-9960
- */
- void getLightIntLowThreshold(uint16_t &threshold)
- {
- uint8_t val_byte;
- threshold = 0;
-
- /* Read value from ambient light low threshold, low byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_AILTL) ;
- threshold = val_byte;
-
- /* Read value from ambient light low threshold, high byte register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AILTH, val_byte) ;
- threshold = threshold + ((uint16_t)val_byte << 8);
- }
-
- /**
- * @brief Sets the low threshold for ambient light interrupts
- *
- * @param[in] threshold low threshold value for interrupt to trigger
- */
-
- void setLightIntLowThreshold(uint16_t threshold)
- {
- uint8_t val_low;
- uint8_t val_high;
-
- /* Break 16-bit threshold into 2 8-bit values */
- val_low = threshold & 0x00FF;
- val_high = (threshold & 0xFF00) >> 8;
-
- /* Write low byte */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AILTL, val_low) ;
-
- /* Write high byte */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AILTH, val_high) ;
-
- }
-
-
- /**
- * @brief Gets the high threshold for ambient light interrupts
- *
- * @param[out] threshold current low threshold stored on the APDS-9960
- */
- void getLightIntHighThreshold(uint16_t &threshold)
- {
- uint8_t val_byte;
- threshold = 0;
-
- /* Read value from ambient light high threshold, low byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_AIHTL);
- threshold = val_byte;
-
- /* Read value from ambient light high threshold, high byte register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AIHTH, val_byte) ;
- threshold = threshold + ((uint16_t)val_byte << 8);
- }
-
- /**
- * @brief Sets the high threshold for ambient light interrupts
- *
- * @param[in] threshold high threshold value for interrupt to trigger
- */
- void setLightIntHighThreshold(uint16_t threshold)
- {
- uint8_t val_low;
- uint8_t val_high;
-
- /* Break 16-bit threshold into 2 8-bit values */
- val_low = threshold & 0x00FF;
- val_high = (threshold & 0xFF00) >> 8;
-
- /* Write low byte */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AIHTL, val_low);
-
- /* Write high byte */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AIHTH, val_high) ;
- }
-
-
- /**
- * @brief Gets the low threshold for proximity interrupts
- *
- * @param[out] threshold current low threshold stored on the APDS-9960
- */
- void getProximityIntLowThreshold(uint8_t &threshold)
- {
- threshold = 0;
-
- /* Read value from proximity low threshold register */
- threshold = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PILT);
-
- }
-
- /**
- * @brief Sets the low threshold for proximity interrupts
- *
- * @param[in] threshold low threshold value for interrupt to trigger
- */
- void setProximityIntLowThreshold(uint8_t threshold)
- {
-
- /* Write threshold value to register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PILT, threshold) ;
- }
-
-
-
- /**
- * @brief Gets the high threshold for proximity interrupts
- *
- * @param[out] threshold current low threshold stored on the APDS-9960
- */
- void getProximityIntHighThreshold(uint8_t &threshold)
- {
- threshold = 0;
-
- /* Read value from proximity low threshold register */
- threshold = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PIHT) ;
-
- }
-
- /**
- * @brief Sets the high threshold for proximity interrupts
- *
- * @param[in] threshold high threshold value for interrupt to trigger
- */
- void setProximityIntHighThreshold(uint8_t threshold)
- {
-
- /* Write threshold value to register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PIHT, threshold) ;
- }
-
- /**
- * @brief Gets if ambient light interrupts are enabled or not
- *
- * @return 1 if interrupts are enabled, 0 if not. 0xFF on error.
- */
- uint8_t getAmbientLightIntEnable()
- {
- uint8_t val;
-
- /* Read value from ENABLE register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ;
-
- /* Shift and mask out AIEN bit */
- val = (val >> 4) & 0b00000001;
-
- return val;
- }
-
- /**
- * @brief Turns ambient light interrupts on or off
- *
- * @param[in] enable 1 to enable interrupts, 0 to turn them off
- */
- void setAmbientLightIntEnable(uint8_t enable)
- {
- uint8_t val;
-
- /* Read value from ENABLE register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE);
-
- /* Set bits in register to given value */
- enable &= 0b00000001;
- enable = enable << 4;
- val &= 0b11101111;
- val |= enable;
-
- /* Write register value back into ENABLE register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ENABLE, val) ;
- }
-
- /**
- * @brief Gets if proximity interrupts are enabled or not
- *
- * @return 1 if interrupts are enabled, 0 if not. 0xFF on error.
- */
- uint8_t getProximityIntEnable()
- {
- uint8_t val;
-
- /* Read value from ENABLE register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ;
-
- /* Shift and mask out PIEN bit */
- val = (val >> 5) & 0b00000001;
-
- return val;
- }
-
- /**
- * @brief Turns proximity interrupts on or off
- *
- * @param[in] enable 1 to enable interrupts, 0 to turn them off
- */
- void setProximityIntEnable(uint8_t enable)
- {
- uint8_t val;
-
- /* Read value from ENABLE register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ;
-
- /* Set bits in register to given value */
- enable &= 0b00000001;
- enable = enable << 5;
- val &= 0b11011111;
- val |= enable;
-
- /* Write register value back into ENABLE register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ENABLE, val) ;
- }
-
- /**
- * @brief Gets if gesture interrupts are enabled or not
- *
- * @return 1 if interrupts are enabled, 0 if not. 0xFF on error.
- */
- uint8_t getGestureIntEnable()
- {
- uint8_t val;
-
- /* Read value from GCONF4 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ;
-
- /* Shift and mask out GIEN bit */
- val = (val >> 1) & 0b00000001;
-
- return val;
- }
-
- /**
- * @brief Turns gesture-related interrupts on or off
- *
- * @param[in] enable 1 to enable interrupts, 0 to turn them off
- */
- void setGestureIntEnable(uint8_t enable)
- {
- uint8_t val;
-
- /* Read value from GCONF4 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ;
-
- /* Set bits in register to given value */
- enable &= 0b00000001;
- enable = enable << 1;
- val &= 0b11111101;
- val |= enable;
-
- /* Write register value back into GCONF4 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF4, val) ;
- }
-
- /**
- * @brief Clears the ambient light interrupt
- *
- */
- void clearAmbientLightInt()
- {
- uint8_t throwaway;
- throwaway = I2cRead8(APDS9960_I2C_ADDR, APDS9960_AICLEAR);
- }
-
- /**
- * @brief Clears the proximity interrupt
- *
- */
- void clearProximityInt()
- {
- uint8_t throwaway;
- throwaway = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PICLEAR) ;
-
- }
-
- /**
- * @brief Tells if the gesture state machine is currently running
- *
- * @return 1 if gesture state machine is running, 0 if not. 0xFF on error.
- */
- uint8_t getGestureMode()
- {
- uint8_t val;
-
- /* Read value from GCONF4 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ;
-
- /* Mask out GMODE bit */
- val &= 0b00000001;
-
- return val;
- }
-
- /**
- * @brief Tells the state machine to either enter or exit gesture state machine
- *
- * @param[in] mode 1 to enter gesture state machine, 0 to exit.
- */
- void setGestureMode(uint8_t mode)
- {
- uint8_t val;
-
- /* Read value from GCONF4 register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ;
-
- /* Set bits in register to given value */
- mode &= 0b00000001;
- val &= 0b11111110;
- val |= mode;
-
- /* Write register value back into GCONF4 register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF4, val) ;
- }
-
-
-bool APDS9960_init()
-{
- /* Set default values for ambient light and proximity registers */
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, DEFAULT_ATIME) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_WTIME, DEFAULT_WTIME) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PPULSE, DEFAULT_PROX_PPULSE) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_POFFSET_UR, DEFAULT_POFFSET_UR) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_POFFSET_DL, DEFAULT_POFFSET_DL) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG1, DEFAULT_CONFIG1) ;
-
- setLEDDrive(DEFAULT_LDRIVE);
-
- setProximityGain(DEFAULT_PGAIN);
-
- setAmbientLightGain(DEFAULT_AGAIN);
-
- setProxIntLowThresh(DEFAULT_PILT) ;
-
- setProxIntHighThresh(DEFAULT_PIHT);
-
- setLightIntLowThreshold(DEFAULT_AILT) ;
-
- setLightIntHighThreshold(DEFAULT_AIHT) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PERS, DEFAULT_PERS) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG2, DEFAULT_CONFIG2) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG3, DEFAULT_CONFIG3) ;
-
- /* Set default values for gesture sense registers */
- setGestureEnterThresh(DEFAULT_GPENTH);
-
- setGestureExitThresh(DEFAULT_GEXTH) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF1, DEFAULT_GCONF1) ;
-
- setGestureGain(DEFAULT_GGAIN) ;
-
- setGestureLEDDrive(DEFAULT_GLDRIVE) ;
-
- setGestureWaitTime(DEFAULT_GWTIME) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_U, DEFAULT_GOFFSET) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_D, DEFAULT_GOFFSET) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_L, DEFAULT_GOFFSET) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_R, DEFAULT_GOFFSET) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GPULSE, DEFAULT_GPULSE) ;
-
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF3, DEFAULT_GCONF3) ;
-
- setGestureIntEnable(DEFAULT_GIEN);
-
- return true;
-}
-/*******************************************************************************
- * Public methods for controlling the APDS-9960
- ******************************************************************************/
-
-/**
- * @brief Reads and returns the contents of the ENABLE register
- *
- * @return Contents of the ENABLE register. 0xFF if error.
- */
-uint8_t getMode()
-{
- uint8_t enable_value;
-
- /* Read current ENABLE register */
- enable_value = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ;
-
- return enable_value;
-}
-
-/**
- * @brief Enables or disables a feature in the APDS-9960
- *
- * @param[in] mode which feature to enable
- * @param[in] enable ON (1) or OFF (0)
- */
-void setMode(uint8_t mode, uint8_t enable)
-{
- uint8_t reg_val;
-
- /* Read current ENABLE register */
- reg_val = getMode();
-
-
- /* Change bit(s) in ENABLE register */
- enable = enable & 0x01;
- if( mode >= 0 && mode <= 6 ) {
- if (enable) {
- reg_val |= (1 << mode);
- } else {
- reg_val &= ~(1 << mode);
- }
- } else if( mode == ALL ) {
- if (enable) {
- reg_val = 0x7F;
- } else {
- reg_val = 0x00;
- }
- }
-
- /* Write value back to ENABLE register */
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ENABLE, reg_val) ;
-}
-
-/**
- * @brief Starts the light (R/G/B/Ambient) sensor on the APDS-9960
- *
- * @param[in] interrupts true to enable hardware interrupt on high or low light
- */
-void enableLightSensor(bool interrupts)
-{
-
- /* Set default gain, interrupts, enable power, and enable sensor */
- setAmbientLightGain(DEFAULT_AGAIN);
- if( interrupts ) {
- setAmbientLightIntEnable(1) ;
-
- }
- else {
- setAmbientLightIntEnable(0);
- }
- enablePower() ;
- setMode(AMBIENT_LIGHT, 1) ;
-}
-
-/**
- * @brief Ends the light sensor on the APDS-9960
- *
- */
-void disableLightSensor()
-{
- setAmbientLightIntEnable(0) ;
- setMode(AMBIENT_LIGHT, 0) ;
-}
-
-/**
- * @brief Starts the proximity sensor on the APDS-9960
- *
- * @param[in] interrupts true to enable hardware external interrupt on proximity
- */
-void enableProximitySensor(bool interrupts)
-{
- /* Set default gain, LED, interrupts, enable power, and enable sensor */
- setProximityGain(DEFAULT_PGAIN);
- setLEDDrive(DEFAULT_LDRIVE) ;
- if( interrupts ) {
- setProximityIntEnable(1) ;
- } else {
- setProximityIntEnable(0) ;
- }
- enablePower();
- setMode(PROXIMITY, 1) ;
-}
-
-/**
- * @brief Ends the proximity sensor on the APDS-9960
- *
- */
-void disableProximitySensor()
-{
- setProximityIntEnable(0) ;
- setMode(PROXIMITY, 0) ;
-}
-
-/**
- * @brief Starts the gesture recognition engine on the APDS-9960
- *
- * @param[in] interrupts true to enable hardware external interrupt on gesture
- */
-void enableGestureSensor(bool interrupts)
-{
-
- /* Enable gesture mode
- Set ENABLE to 0 (power off)
- Set WTIME to 0xFF
- Set AUX to LED_BOOST_300
- Enable PON, WEN, PEN, GEN in ENABLE
- */
- resetGestureParameters();
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_WTIME, 0xFF) ;
- I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PPULSE, DEFAULT_GESTURE_PPULSE) ;
- setLEDBoost(LED_BOOST_100); // tip from jonn26 - 100 for 300
- if( interrupts ) {
- setGestureIntEnable(1) ;
- } else {
- setGestureIntEnable(0) ;
- }
- setGestureMode(1);
- enablePower() ;
- setMode(WAIT, 1) ;
- setMode(PROXIMITY, 1) ;
- setMode(GESTURE, 1);
-}
-
-/**
- * @brief Ends the gesture recognition engine on the APDS-9960
- *
- */
-void disableGestureSensor()
-{
- resetGestureParameters();
- setGestureIntEnable(0) ;
- setGestureMode(0) ;
- setMode(GESTURE, 0) ;
-}
-
-/**
- * @brief Determines if there is a gesture available for reading
- *
- * @return True if gesture available. False otherwise.
- */
-bool isGestureAvailable()
-{
- uint8_t val;
-
- /* Read value from GSTATUS register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GSTATUS) ;
-
- /* Shift and mask out GVALID bit */
- val &= APDS9960_GVALID;
-
- /* Return true/false based on GVALID bit */
- if( val == 1) {
- return true;
- } else {
- return false;
- }
-}
-
-/**
- * @brief Processes a gesture event and returns best guessed gesture
- *
- * @return Number corresponding to gesture. -1 on error.
- */
-int16_t readGesture()
-{
- uint8_t fifo_level = 0;
- uint8_t bytes_read = 0;
- uint8_t fifo_data[128];
- uint8_t gstatus;
- uint16_t motion;
- uint16_t i;
- uint8_t gesture_loop_counter = 0; // don't loop forever later
-
- /* Make sure that power and gesture is on and data is valid */
- if( !isGestureAvailable() || !(getMode() & 0b01000001) ) {
- return DIR_NONE;
- }
-
- /* Keep looping as long as gesture data is valid */
- while(1) {
- if (gesture_loop_counter == APDS9960_MAX_GESTURE_CYCLES){ // We will escape after a few loops
- disableGestureSensor(); // stop the sensor to prevent problems with power consumption/blocking and return to the main loop
- APDS9960_overload = true; // we report this as "long"-gesture
- char log[LOGSZ];
- snprintf_P(log, sizeof(log), PSTR("Sensor overload"));
- AddLog_P(LOG_LEVEL_DEBUG, log);
- }
- gesture_loop_counter += 1;
- /* Wait some time to collect next batch of FIFO data */
- delay(FIFO_PAUSE_TIME);
-
- /* Get the contents of the STATUS register. Is data still valid? */
- gstatus = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GSTATUS);
-
- /* If we have valid data, read in FIFO */
- if( (gstatus & APDS9960_GVALID) == APDS9960_GVALID ) {
-
- /* Read the current FIFO level */
- fifo_level = I2cRead8(APDS9960_I2C_ADDR,APDS9960_GFLVL) ;
-
-#if DEBUG
- Serial.print("FIFO Level: ");
- Serial.println(fifo_level);
-#endif
-
- /* If there's stuff in the FIFO, read it into our data block */
- if( fifo_level > 0) {
- bytes_read = wireReadDataBlock( APDS9960_GFIFO_U,
- (uint8_t*)fifo_data,
- (fifo_level * 4) );
- if( bytes_read == -1 ) {
- return ERROR;
- }
-#if DEBUG
- Serial.print("FIFO Dump: ");
- for ( i = 0; i < bytes_read; i++ ) {
- Serial.print(fifo_data[i]);
- Serial.print(" ");
- }
- Serial.println();
-#endif
-
- /* If at least 1 set of data, sort the data into U/D/L/R */
- if( bytes_read >= 4 ) {
- for( i = 0; i < bytes_read; i += 4 ) {
- gesture_data_.u_data[gesture_data_.index] = \
- fifo_data[i + 0];
- gesture_data_.d_data[gesture_data_.index] = \
- fifo_data[i + 1];
- gesture_data_.l_data[gesture_data_.index] = \
- fifo_data[i + 2];
- gesture_data_.r_data[gesture_data_.index] = \
- fifo_data[i + 3];
- gesture_data_.index++;
- gesture_data_.total_gestures++;
- }
-
-#if DEBUG
- Serial.print("Up Data: ");
- for ( i = 0; i < gesture_data_.total_gestures; i++ ) {
- Serial.print(gesture_data_.u_data[i]);
- Serial.print(" ");
- }
- Serial.println();
-#endif
-
- /* Filter and process gesture data. Decode near/far state */
- if( processGestureData() ) {
- if( decodeGesture() ) {
- //***TODO: U-Turn Gestures
-#if DEBUG
- //Serial.println(gesture_motion_);
-#endif
- }
- }
-
- /* Reset data */
- gesture_data_.index = 0;
- gesture_data_.total_gestures = 0;
- }
- }
- } else {
-
- /* Determine best guessed gesture and clean up */
- delay(FIFO_PAUSE_TIME);
- decodeGesture();
- motion = gesture_motion_;
-#if DEBUG
- Serial.print("END: ");
- Serial.println(gesture_motion_);
-#endif
- resetGestureParameters();
- return motion;
- }
- }
-}
-
-/**
- * Turn the APDS-9960 on
- *
- */
-void enablePower()
-{
- setMode(POWER, 1) ;
-}
-
-/**
- * Turn the APDS-9960 off
- *
- */
-void disablePower()
-{
- setMode(POWER, 0) ;
-}
-
-/*******************************************************************************
- * Ambient light and color sensor controls
- ******************************************************************************/
-
-/**
- * @brief Reads the ambient (clear) light level as a 16-bit value
- *
- * @param[out] val value of the light sensor.
- */
-void readAmbientLight(uint16_t &val)
-{
- uint8_t val_byte;
- val = 0;
-
- /* Read value from clear channel, low byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CDATAL);
- val = val_byte;
-
- /* Read value from clear channel, high byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CDATAH);
- val = val + ((uint16_t)val_byte << 8);
-}
-
-/**
- * @brief Reads the red light level as a 16-bit value
- *
- * @param[out] val value of the light sensor.
- */
-void readRedLight(uint16_t &val)
-{
- uint8_t val_byte;
- val = 0;
-
- /* Read value from clear channel, low byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_RDATAL) ;
- val = val_byte;
-
- /* Read value from clear channel, high byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_RDATAH) ;
- val = val + ((uint16_t)val_byte << 8);
-}
-
-/**
- * @brief Reads the green light level as a 16-bit value
- *
- * @param[out] val value of the light sensor.
- */
-void readGreenLight(uint16_t &val)
-{
- uint8_t val_byte;
- val = 0;
-
- /* Read value from clear channel, low byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GDATAL) ;
- val = val_byte;
-
- /* Read value from clear channel, high byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GDATAH) ;
- val = val + ((uint16_t)val_byte << 8);
-}
-
-/**
- * @brief Reads the red light level as a 16-bit value
- *
- * @param[out] val value of the light sensor.
- */
-void readBlueLight(uint16_t &val)
-{
- uint8_t val_byte;
- val = 0;
-
- /* Read value from clear channel, low byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_BDATAL) ;
- val = val_byte;
-
- /* Read value from clear channel, high byte register */
- val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_BDATAH) ;
- val = val + ((uint16_t)val_byte << 8);
-}
-
-/*******************************************************************************
- * Proximity sensor controls
- ******************************************************************************/
-
-/**
- * @brief Reads the proximity level as an 8-bit value
- *
- * @param[out] val value of the proximity sensor.
- */
-void readProximity(uint8_t &val)
-{
- val = 0;
-
- /* Read value from proximity data register */
- val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PDATA) ;
-}
-
-/*******************************************************************************
- * High-level gesture controls
- ******************************************************************************/
-
-/**
- * @brief Resets all the parameters in the gesture data member
- */
-void resetGestureParameters()
-{
- gesture_data_.index = 0;
- gesture_data_.total_gestures = 0;
-
- gesture_ud_delta_ = 0;
- gesture_lr_delta_ = 0;
-
- gesture_ud_count_ = 0;
- gesture_lr_count_ = 0;
-
- gesture_state_ = 0;
- gesture_motion_ = DIR_NONE;
-}
-
-/**
- * @brief Processes the raw gesture data to determine swipe direction
- *
- * @return True if near or far state seen. False otherwise.
- */
-bool processGestureData()
-{
- uint8_t u_first = 0;
- uint8_t d_first = 0;
- uint8_t l_first = 0;
- uint8_t r_first = 0;
- uint8_t u_last = 0;
- uint8_t d_last = 0;
- uint8_t l_last = 0;
- uint8_t r_last = 0;
- uint16_t ud_ratio_first;
- uint16_t lr_ratio_first;
- uint16_t ud_ratio_last;
- uint16_t lr_ratio_last;
- uint16_t ud_delta;
- uint16_t lr_delta;
- uint16_t i;
-
- /* If we have less than 4 total gestures, that's not enough */
- if( gesture_data_.total_gestures <= 4 ) {
- return false;
- }
-
- /* Check to make sure our data isn't out of bounds */
- if( (gesture_data_.total_gestures <= 32) && \
- (gesture_data_.total_gestures > 0) ) {
-
- /* Find the first value in U/D/L/R above the threshold */
- for( i = 0; i < gesture_data_.total_gestures; i++ ) {
- if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) &&
- (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) &&
- (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) &&
- (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) {
-
- u_first = gesture_data_.u_data[i];
- d_first = gesture_data_.d_data[i];
- l_first = gesture_data_.l_data[i];
- r_first = gesture_data_.r_data[i];
- break;
- }
- }
-
- /* If one of the _first values is 0, then there is no good data */
- if( (u_first == 0) || (d_first == 0) || \
- (l_first == 0) || (r_first == 0) ) {
-
- return false;
- }
- /* Find the last value in U/D/L/R above the threshold */
- for( i = gesture_data_.total_gestures - 1; i >= 0; i-- ) {
-#if DEBUG
- Serial.print(F("Finding last: "));
- Serial.print(F("U:"));
- Serial.print(gesture_data_.u_data[i]);
- Serial.print(F(" D:"));
- Serial.print(gesture_data_.d_data[i]);
- Serial.print(F(" L:"));
- Serial.print(gesture_data_.l_data[i]);
- Serial.print(F(" R:"));
- Serial.println(gesture_data_.r_data[i]);
-#endif
- if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) &&
- (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) &&
- (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) &&
- (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) {
-
- u_last = gesture_data_.u_data[i];
- d_last = gesture_data_.d_data[i];
- l_last = gesture_data_.l_data[i];
- r_last = gesture_data_.r_data[i];
- break;
- }
- }
- }
-
- /* Calculate the first vs. last ratio of up/down and left/right */
- ud_ratio_first = ((u_first - d_first) * 100) / (u_first + d_first);
- lr_ratio_first = ((l_first - r_first) * 100) / (l_first + r_first);
- ud_ratio_last = ((u_last - d_last) * 100) / (u_last + d_last);
- lr_ratio_last = ((l_last - r_last) * 100) / (l_last + r_last);
-
-#if DEBUG
- Serial.print(F("Last Values: "));
- Serial.print(F("U:"));
- Serial.print(u_last);
- Serial.print(F(" D:"));
- Serial.print(d_last);
- Serial.print(F(" L:"));
- Serial.print(l_last);
- Serial.print(F(" R:"));
- Serial.println(r_last);
-
- Serial.print(F("Ratios: "));
- Serial.print(F("UD Fi: "));
- Serial.print(ud_ratio_first);
- Serial.print(F(" UD La: "));
- Serial.print(ud_ratio_last);
- Serial.print(F(" LR Fi: "));
- Serial.print(lr_ratio_first);
- Serial.print(F(" LR La: "));
- Serial.println(lr_ratio_last);
-#endif
-
- /* Determine the difference between the first and last ratios */
- ud_delta = ud_ratio_last - ud_ratio_first;
- lr_delta = lr_ratio_last - lr_ratio_first;
-
-#if DEBUG
- Serial.print("Deltas: ");
- Serial.print("UD: ");
- Serial.print(ud_delta);
- Serial.print(" LR: ");
- Serial.println(lr_delta);
-#endif
-
- /* Accumulate the UD and LR delta values */
- gesture_ud_delta_ += ud_delta;
- gesture_lr_delta_ += lr_delta;
-
-#if DEBUG
- Serial.print("Accumulations: ");
- Serial.print("UD: ");
- Serial.print(gesture_ud_delta_);
- Serial.print(" LR: ");
- Serial.println(gesture_lr_delta_);
-#endif
-
- /* Determine U/D gesture */
- if( gesture_ud_delta_ >= GESTURE_SENSITIVITY_1 ) {
- gesture_ud_count_ = 1;
- } else if( gesture_ud_delta_ <= -GESTURE_SENSITIVITY_1 ) {
- gesture_ud_count_ = -1;
- } else {
- gesture_ud_count_ = 0;
- }
-
- /* Determine L/R gesture */
- if( gesture_lr_delta_ >= GESTURE_SENSITIVITY_1 ) {
- gesture_lr_count_ = 1;
- } else if( gesture_lr_delta_ <= -GESTURE_SENSITIVITY_1 ) {
- gesture_lr_count_ = -1;
- } else {
- gesture_lr_count_ = 0;
- }
-
-#if DEBUG
- Serial.print("UD_CT: ");
- Serial.print(gesture_ud_count_);
- Serial.print(" LR_CT: ");
- Serial.print(gesture_lr_count_);
- Serial.println("----------");
-#endif
-
- return false;
-}
-
-/**
- * @brief Determines swipe direction or near/far state
- *
- * @return True if near/far event. False otherwise.
- */
-bool decodeGesture()
-{
-
- /* Determine swipe direction */
- if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 0) ) {
- gesture_motion_ = DIR_UP;
- } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 0) ) {
- gesture_motion_ = DIR_DOWN;
- } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 1) ) {
- gesture_motion_ = DIR_RIGHT;
- } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == -1) ) {
- gesture_motion_ = DIR_LEFT;
- } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 1) ) {
- if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {
- gesture_motion_ = DIR_UP;
- } else {
- gesture_motion_ = DIR_RIGHT;
- }
- } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == -1) ) {
- if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {
- gesture_motion_ = DIR_DOWN;
- } else {
- gesture_motion_ = DIR_LEFT;
- }
- } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == -1) ) {
- if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {
- gesture_motion_ = DIR_UP;
- } else {
- gesture_motion_ = DIR_LEFT;
- }
- } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 1) ) {
- if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {
- gesture_motion_ = DIR_DOWN;
- } else {
- gesture_motion_ = DIR_RIGHT;
- }
- } else {
- return false;
- }
-
- return true;
-}
-
-void handleGesture() {
- if (isGestureAvailable() ) {
- char log[LOGSZ];
- switch (readGesture()) {
- case DIR_UP:
- snprintf_P(log, sizeof(log), PSTR("UP"));
- snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Up"));
- break;
- case DIR_DOWN:
- snprintf_P(log, sizeof(log), PSTR("DOWN"));
- snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Down"));
- break;
- case DIR_LEFT:
- snprintf_P(log, sizeof(log), PSTR("LEFT"));
- snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Left"));
- break;
- case DIR_RIGHT:
- snprintf_P(log, sizeof(log), PSTR("RIGHT"));
- snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Right"));
- break;
- default:
- if(APDS9960_overload)
- {
- snprintf_P(log, sizeof(log), PSTR("LONG"));
- snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Long"));
- }
- else{
- snprintf_P(log, sizeof(log), PSTR("NONE"));
- snprintf_P(currentGesture, sizeof(currentGesture), PSTR("None"));
- }
- }
- AddLog_P(LOG_LEVEL_DEBUG, log);
-
- mqtt_data[0] = '\0';
- if (MqttShowSensor()) {
- MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
-#ifdef USE_RULES
- RulesTeleperiod(); // Allow rule based HA messages
-#endif // USE_RULES
- }
- }
-}
-
-
-void APDS9960_loop()
-{
- if (recovery_loop_counter > 0){
- recovery_loop_counter -= 1;
- }
- if (recovery_loop_counter == 1 && APDS9960_overload){ //restart sensor just before the end of recovery from long press
- enableGestureSensor(false);
- APDS9960_overload = false;
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Gesture\":\"On\"}"));
- MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data); // only after the long break we report, that we are online again
- gesture_mode = 1;
- }
-
- if (gesture_mode) {
- if (recovery_loop_counter == 0){
- handleGesture();
-
- if (APDS9960_overload)
- {
- disableGestureSensor();
- recovery_loop_counter = APDS9960_LONG_RECOVERY; // long pause after overload/long press - number of stateloops
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Gesture\":\"Off\"}"));
- MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
- gesture_mode = 0;
- }
- }
- }
-}
-
-bool APDS9960_detect(void)
-{
- if (APDS9960type) {
- return true;
- }
-
- boolean success = false;
- APDS9960type = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ID);
-
- if (APDS9960type == APDS9960_CHIPID_1 || APDS9960type == APDS9960_CHIPID_2) {
- strcpy_P(APDS9960stype, PSTR("APDS9960"));
- snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, APDS9960stype, APDS9960_I2C_ADDR);
- AddLog(LOG_LEVEL_DEBUG);
- if (APDS9960_init()) {
- success = true;
- AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "APDS9960 initialized"));
- enableGestureSensor(false);
- }
- } else {
- snprintf_P(log_data, sizeof(log_data), PSTR("APDS9960 not found at address 0x%x"), APDS9960_I2C_ADDR);
- AddLog(LOG_LEVEL_DEBUG);
- }
- currentGesture[0] = '\0';
- return success;
-}
-
-/*********************************************************************************************\
- * Presentation
-\*********************************************************************************************/
-
-void APDS9960_show(boolean json)
-{
- if (!APDS9960type) {
- return;
- }
- if (!gesture_mode) {
- char red_chr[10];
- char green_chr[10];
- char blue_chr[10];
- char ambient_chr[10];
- char prox_chr[10];
- uint16_t val;
- uint8_t val_prox;
-
- readRedLight(val);
- sprintf (red_chr, "%u", val);
- readGreenLight(val);
- sprintf (green_chr, "%u", val);
- readBlueLight(val);
- sprintf (blue_chr, "%u", val );
- readAmbientLight(val);
- sprintf (ambient_chr, "%u", val);
-
- readProximity(val_prox);
- sprintf (prox_chr, "%u", val_prox );
-
- if (json) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"Red\":%s,\"Green\":%s,\"Blue\":%s,\"Ambient\":%s,\"Proximity\":%s}"),
- mqtt_data, APDS9960stype, red_chr, green_chr, blue_chr, ambient_chr, prox_chr);
-#ifdef USE_WEBSERVER
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_APDS_9960_SNS, mqtt_data, red_chr, green_chr, blue_chr, ambient_chr, prox_chr );
-#endif // USE_WEBSERVER
- }
- }
- else {
- if (json && (currentGesture[0] != '\0' )) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"%s\":1}"), mqtt_data, APDS9960stype, currentGesture);
- currentGesture[0] = '\0';
- }
- }
-}
-
-/*********************************************************************************************\
- * Command Sensor27
- *
- * Command | Payload | Description
- * ---------|---------|--------------------------
- * Sensor27 | | Show current gesture mode
- * Sensor27 | 0 / Off | Disable gesture mode
- * Sensor27 | 1 / On | Enable gesture mode
-\*********************************************************************************************/
-
-bool APDS9960CommandSensor()
-{
- boolean serviced = true;
-
- switch (XdrvMailbox.payload) {
- case 0: // Off
- disableGestureSensor();
- gesture_mode = 0;
- enableLightSensor(false);
- enableProximitySensor(false);
- break;
- case 1: // On
- if (APDS9960type) {
- disableLightSensor();
- disableProximitySensor();
- enableGestureSensor(false);
- gesture_mode = 1;
- }
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_27, GetStateText(gesture_mode));
-
- return serviced;
-}
-
-/*********************************************************************************************\
- * Interface
-\*********************************************************************************************/
-
-boolean Xsns27(byte function)
-{
- boolean result = false;
-
- if (i2c_flg) {
- if (FUNC_INIT == function) {
- APDS9960_detect();
- } else if (APDS9960type) {
- switch (function) {
- case FUNC_EVERY_50_MSECOND:
- APDS9960_loop();
- break;
- case FUNC_COMMAND:
- if (XSNS_27 == XdrvMailbox.index) {
- result = APDS9960CommandSensor();
- }
- break;
- case FUNC_JSON_APPEND:
- APDS9960_show(1);
- break;
-#ifdef USE_WEBSERVER
- case FUNC_WEB_APPEND:
- APDS9960_show(0);
- break;
-#endif // USE_WEBSERVER
- }
- }
- }
- return result;
-}
-#endif // USE_APDS9960
-#endif // USE_I2C