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