diff --git a/src/configuration.h b/src/configuration.h index d319ddb0a..4138d6950 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -187,6 +187,8 @@ along with this program. If not, see . // Touchscreen // ----------------------------------------------------------------------------- #define FT6336U_ADDR 0x48 +#define CST226SE_ADDR 0x1A +#define CST226SE_ADDR_ALT 0x5A // ----------------------------------------------------------------------------- // BIAS-T Generator diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index c363db1b5..e43bc7017 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -71,6 +71,7 @@ class ScanI2C DPS310, LTR390UV, TCA8418KB, + CST226SE, } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 9781cbf56..740649a1b 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -434,13 +434,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address); SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address); SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(CST226SE_ADDR, CST226SE, "CST226SE", (uint8_t)addr.address); #ifdef HAS_TPS65233 SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address); #endif case MLX90614_ADDR_DEF: - registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1); - if (registerValue == 0x5a) { + // Do we have the MLX90614 or the MPR121KB or the CST226SE + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x06), 1); + if (registerValue == 0xAB) { + type = CST226SE; + logFoundDevice("CST226SE", (uint8_t)addr.address); + } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1) == 0x5a) { type = MLX90614; logFoundDevice("MLX90614", (uint8_t)addr.address); } else { diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index ad0b94efe..95b21c93f 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -39,6 +39,7 @@ along with this program. If not, see . #include "graphics/ScreenFonts.h" #include "graphics/images.h" #include "input/ScanAndSelect.h" +#include "input/TouchScreenCST226SE.h" #include "input/TouchScreenImpl1.h" #include "main.h" #include "mesh-pb-constants.h" @@ -1104,7 +1105,7 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const NodeStat char usersString[20]; snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal()); #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(ILI9488_CS) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x, y + 3, 8, 8, imgUser); #else @@ -1523,7 +1524,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ screen->drawColumns(display, x, y, fields); } -#if defined(ESP_PLATFORM) && defined(USE_ST7789) +#if defined(ESP_PLATFORM) && (defined(USE_ST7789) || defined(USE_ST7796)) SPIClass SPI1(HSPI); #endif @@ -1541,6 +1542,13 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #else dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); #endif +#elif defined(USE_ST7796) +#ifdef ESP_PLATFORM + dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7796_SDA, + ST7796_MISO, ST7796_SCK, TFT_SPI_FREQUENCY); +#else + dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); +#endif #elif defined(USE_SSD1306) dispdev = new SSD1306Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); @@ -1632,6 +1640,15 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) pinMode(VTFT_LEDA, OUTPUT); digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); #endif +#endif +#ifdef USE_ST7796 + ui->init(); +#ifdef ESP_PLATFORM + analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT); +#else + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); +#endif #endif enabled = true; setInterval(0); // Draw ASAP @@ -1666,6 +1683,21 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) nrf_gpio_cfg_default(ST7789_NSS); #endif #endif +#ifdef USE_ST7796 + SPI1.end(); +#if defined(ARCH_ESP32) + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, LOW); + pinMode(ST7796_RESET, ANALOG); + pinMode(ST7796_RS, ANALOG); + pinMode(ST7796_NSS, ANALOG); +#else + nrf_gpio_cfg_default(VTFT_LEDA); + nrf_gpio_cfg_default(ST7796_RESET); + nrf_gpio_cfg_default(ST7796_RS); + nrf_gpio_cfg_default(ST7796_NSS); +#endif +#endif #ifdef T_WATCH_S3 PMU->disablePowerOutput(XPOWERS_ALDO2); @@ -1695,6 +1727,10 @@ void Screen::setup() // Heltec T114 and T190: honor a custom text color, if defined in variant.h static_cast(dispdev)->setRGB(TFT_MESH); #endif +#if defined(USE_ST7796) && defined(TFT_MESH) + // Custom text color, if defined in variant.h + static_cast(dispdev)->setRGB(TFT_MESH); +#endif // Initialising the UI will init the display too. ui->init(); @@ -1755,6 +1791,8 @@ void Screen::setup() static_cast(dispdev)->flipScreenVertically(); #elif defined(USE_ST7789) static_cast(dispdev)->flipScreenVertically(); +#elif defined(USE_ST7796) + static_cast(dispdev)->mirrorScreen(); #else dispdev->flipScreenVertically(); #endif @@ -1786,10 +1824,13 @@ void Screen::setup() new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast(dispdev)->getTouch); touchScreenImpl1->init(); } -#elif HAS_TOUCHSCREEN +#elif HAS_TOUCHSCREEN && !HAS_CST226SE touchScreenImpl1 = new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast(dispdev)->getTouch); touchScreenImpl1->init(); +#elif HAS_TOUCHSCREEN && HAS_CST226SE + touchScreenCST226SE = new TouchScreenCST226SE(TFT_HEIGHT, TFT_WIDTH, TouchScreenCST226SE::forwardGetTouch); + touchScreenCST226SE->init(); #endif // Subscribe to status updates @@ -2492,7 +2533,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat, (storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || ARCH_PORTDUINO) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(HX8357_CS) || defined(ILI9488_CS) || \ + ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL1); @@ -2504,7 +2546,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 #endif } else { #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(HX8357_CS) || defined(ILI9488_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8, imgSFL1); @@ -2519,7 +2561,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 } else { // TODO: Raspberry Pi supports more than just the one screen size #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || ARCH_PORTDUINO) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(HX8357_CS) || defined(ILI9488_CS) || \ + ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL1); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index ce416156f..1f63d1fe6 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -47,6 +47,8 @@ class Screen #include #elif defined(USE_ST7789) #include +#elif defined(USE_ST7796) +#include #else // the SH1106/SSD1306 variant is auto-detected #include diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index 0be0dc814..a91efdba1 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -65,8 +65,8 @@ #endif #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS)) || \ - defined(ILI9488_CS) && !defined(DISPLAY_FORCE_SMALL_FONTS) + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(HX8357_CS) || defined(ILI9488_CS)) && \ + !defined(DISPLAY_FORCE_SMALL_FONTS) // The screen is bigger so use bigger fonts #define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19 #define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 28 diff --git a/src/graphics/images.h b/src/graphics/images.h index 069839a16..f34b51c9b 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -21,7 +21,8 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03 #endif #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || ARCH_PORTDUINO) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(HX8357_CS) || defined(ILI9488_CS) || \ + ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff}; const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f}; diff --git a/src/input/TouchScreenCST226SE.cpp b/src/input/TouchScreenCST226SE.cpp new file mode 100644 index 000000000..3afd20db3 --- /dev/null +++ b/src/input/TouchScreenCST226SE.cpp @@ -0,0 +1,121 @@ +#include "TouchScreenCST226SE.h" +#include "variant.h" + +#ifdef HAS_CST226SE + +#ifndef TOUCH_IRQ +#define TOUCH_IRQ -1 +#endif + +#include "PowerFSM.h" +#include "Wire.h" +#include "configuration.h" +#include "modules/ExternalNotificationModule.h" + +volatile bool isPressed = false; + +TouchScreenCST226SE *TouchScreenCST226SE::instance = nullptr; +TouchScreenCST226SE *touchScreenCST226SE; + +TouchScreenCST226SE::TouchScreenCST226SE(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *)) + : TouchScreenBase("CST226", width, height), _getTouch(getTouch) +{ + instance = this; +} + +void TouchScreenCST226SE::init() +{ + touch.setPins(-1, TOUCH_IRQ); + touch.setTouchDrvModel(TouchDrv_CST226); + for (uint8_t addr : PossibleAddresses) { + if (touch.begin(Wire, addr, I2C_SDA, I2C_SCL)) { + i2cAddress = addr; + attachInterrupt( + TOUCH_IRQ, []() { isPressed = true; }, FALLING); + LOG_DEBUG("CST226SE init OK at address 0x%02X", addr); + return; + } + } + + LOG_ERROR("CST226SE init failed at all known addresses"); +} + +bool TouchScreenCST226SE::getTouch(int16_t &x, int16_t &y) +{ + if (!touch.isPressed()) { + return false; + } + int16_t x_array[1], y_array[1]; + uint8_t touched = touch.getPoint(x_array, y_array, 1); + if (touched > 0) { + int16_t tx = x_array[0]; + int16_t ty = y_array[0]; + if (tx > (TFT_WIDTH + 10) && tx < (10) && ty > (TFT_HEIGHT + 10) && ty < (10)) { + return false; + } + x = tx; + y = ty; + LOG_DEBUG("TouchScreen touched %dx %dy", x, y); + return true; + } + return false; +} + +bool TouchScreenCST226SE::forwardGetTouch(int16_t *x, int16_t *y) +{ + if (instance) { + return instance->getTouch(*x, *y); + LOG_DEBUG("TouchScreen parsed %dx %dy", x, y); + } else { + return false; + } +} + +void TouchScreenCST226SE::onEvent(const TouchEvent &event) +{ + InputEvent e; + e.source = event.source; + + e.touchX = event.x; + e.touchY = event.y; + + switch (event.touchEvent) { + case TOUCH_ACTION_LEFT: { + e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT); + break; + } + case TOUCH_ACTION_RIGHT: { + e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT); + break; + } + case TOUCH_ACTION_UP: { + e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP); + break; + } + case TOUCH_ACTION_DOWN: { + e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN); + break; + } + case TOUCH_ACTION_DOUBLE_TAP: { + e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT); + break; + } + case TOUCH_ACTION_LONG_PRESS: { + e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL); + break; + } + case TOUCH_ACTION_TAP: { + if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) { + externalNotificationModule->stopNow(); + } else { + powerFSM.trigger(EVENT_INPUT); + } + break; + } + default: + return; + } + this->notifyObservers(&e); +} + +#endif \ No newline at end of file diff --git a/src/input/TouchScreenCST226SE.h b/src/input/TouchScreenCST226SE.h new file mode 100644 index 000000000..26bc7a449 --- /dev/null +++ b/src/input/TouchScreenCST226SE.h @@ -0,0 +1,34 @@ +#pragma once + +#include "variant.h" + +#ifdef HAS_CST226SE + +#include "modules/CannedMessageModule.h" + +#include "TouchDrvCSTXXX.hpp" +#include "TouchScreenBase.h" + +class TouchScreenCST226SE : public TouchScreenBase +{ + public: + TouchScreenCST226SE(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *)); + void init(void); + + static bool forwardGetTouch(int16_t *x, int16_t *y); + bool (*_getTouch)(int16_t *, int16_t *); + virtual bool getTouch(int16_t &x, int16_t &y); + virtual void onEvent(const TouchEvent &event); + + private: + static TouchScreenCST226SE *instance; + TouchDrvCSTXXX touch; + uint8_t i2cAddress = 0; + + static constexpr uint8_t PossibleAddresses[2] = {CST226SE_ADDR, CST226SE_ADDR_ALT}; +}; + +// For global reference in other code +extern TouchScreenCST226SE *touchScreenCST226SE; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index eb93a70d1..f7a163915 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -954,7 +954,7 @@ void setup() // Don't call screen setup until after nodedb is setup (because we need // the current region name) #if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \ - defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) + defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(USE_ST7796) screen->setup(); #elif defined(ARCH_PORTDUINO) if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) { diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 67f0da600..5c6686cd9 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -595,7 +595,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) config.bluetooth.fixed_pin = defaultBLEPin; #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \ - defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) + defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(USE_ST7796) bool hasScreen = true; #ifdef HELTEC_MESH_NODE_T114 uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET); diff --git a/variants/tbeam/platformio.ini b/variants/tbeam/platformio.ini index 9049836a3..41a805849 100644 --- a/variants/tbeam/platformio.ini +++ b/variants/tbeam/platformio.ini @@ -3,11 +3,23 @@ extends = esp32_base board = ttgo-t-beam board_check = true -lib_deps = - ${esp32_base.lib_deps} -build_flags = - ${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam - -DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely. - -DBOARD_HAS_PSRAM +lib_deps = ${esp32_base.lib_deps} +build_flags = ${esp32_base.build_flags} + -D TBEAM_V10 + -I variants/tbeam + -D GPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely. + -D BOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -upload_speed = 921600 \ No newline at end of file +upload_speed = 921600 + +[env:tbeam-displayshield] +extends = env:tbeam + +build_flags = + ${env:tbeam.build_flags} + -D USE_ST7796 + +lib_deps = + ${env:tbeam.lib_deps} + https://github.com/Nasimovy/st7796/archive/refs/tags/1.0.5.zip ; display addon + lewisxhe/SensorLib@0.3.1 ; touchscreen addon diff --git a/variants/tbeam/variant.h b/variants/tbeam/variant.h index 8771c20d2..4cf409165 100644 --- a/variants/tbeam/variant.h +++ b/variants/tbeam/variant.h @@ -42,4 +42,29 @@ #define GPS_UBLOX #define GPS_RX_PIN 34 #define GPS_TX_PIN 12 -// #define GPS_DEBUG \ No newline at end of file +// #define GPS_DEBUG + +// Used when the diplay shield is chosen +#ifdef USE_ST7796 + +#undef EXT_NOTIFY_OUT +#undef LED_STATE_ON +#undef LED_PIN + +#define HAS_CST226SE 1 +#define HAS_TOUCHSCREEN 1 +#define TOUCH_IRQ 35 + +#define ST7796_NSS 25 +#define ST7796_RS 13 // DC +#define ST7796_SDA 14 // MOSI +#define ST7796_SCK 15 +#define ST7796_RESET 2 +#define ST7796_MISO -1 +#define ST7796_BUSY -1 +#define VTFT_LEDA 4 +#define TFT_SPI_FREQUENCY 4000000 +#define TFT_HEIGHT 222 +#define TFT_WIDTH 480 +#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightnes +#endif \ No newline at end of file