diff --git a/platformio.ini b/platformio.ini index f7c73c1902..56aaff32df 100644 --- a/platformio.ini +++ b/platformio.ini @@ -26,6 +26,7 @@ default_envs = tbeam ;default_envs = meshtastic-diy-v1_1 ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink +;default_envs = m5stack-core2 ;default_envs = rak4631 ;default_envs = rak4631_eth_gw ;default_envs = rak2560 @@ -165,4 +166,4 @@ lib_deps = mprograms/QMC5883LCompass@1.2.3 https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d - https://github.com/gjelsoe/STK8xxx-Accelerometer.git#v0.1.1 + https://github.com/gjelsoe/STK8xxx-Accelerometer.git#v0.1.1 \ No newline at end of file diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 0ea1309cc9..7cf8ea6f0e 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -13,6 +13,9 @@ #ifdef ARCH_PORTDUINO #include "platform/portduino/PortduinoGlue.h" #endif +#if defined(M5STACK_CORE2) +#include +#endif #define DEBUG_BUTTONS 0 #if DEBUG_BUTTONS @@ -332,4 +335,88 @@ void ButtonThread::userButtonPressedLongStop() if (millis() > c_holdOffTime) { btnEvent = BUTTON_EVENT_LONG_RELEASED; } -} \ No newline at end of file +} + +#if defined(M5STACK_CORE2) +// Define a constant +const unsigned long LONG_PRESS_THRESHOLD = 5000; // Hold the threshold +const unsigned long DOUBLE_CLICK_THRESHOLD = 1000; // Double-click the threshold +const int MAX_CLICKS = 2; // Maximum hits +// Global variable +unsigned long lastClickTime = 0; // The time of the last click +int clickCount = 0; // Click count +unsigned long touch_start_time; // Touch start time +bool is_touching = false; // Mark whether you are currently touching +void ScreenTouch() +{ + M5.update(); + auto count = M5.Touch.getCount(); + if (count == 0) + return; + for (std::size_t i = 0; i < count; ++i) { + auto t = M5.Touch.getDetail(i); + + // If touch starts + if (t.wasPressed()) { + touch_start_time = millis(); // Record the time when the touch began + is_touching = true; // Set to touch + } + + // Check the current touch status + if (is_touching) { + unsigned long duration = millis() - touch_start_time; + if (duration >= LONG_PRESS_THRESHOLD) { + LOG_INFO("Long Press Detected\n"); + powerFSM.trigger(EVENT_PRESS); + screen->startAlert("Shutting down..."); + screen->forceDisplay(true); + // Executive logic, such as shutdown, display menu, etc + // To avoid duplicate detection, set is_touching to false here + is_touching = false; + M5.Speaker.tone(3000, 300); + delay(1000); + M5.Power.powerOff(); + } + } + // Check if the touch just ended + if (t.wasReleased()) { + if (is_touching) { + unsigned long duration = millis() - touch_start_time; + if (duration < LONG_PRESS_THRESHOLD) { + unsigned long currentTime = millis(); + // Check whether it is a double click + if (currentTime - lastClickTime <= DOUBLE_CLICK_THRESHOLD) { + clickCount++; + if (clickCount == MAX_CLICKS) { + LOG_INFO("Double Click Detected\n"); + M5.Speaker.tone(2000, 100); + service->refreshLocalMeshNode(); + auto sentPosition = service->trySendPosition(NODENUM_BROADCAST, true); + if (screen) { + if (sentPosition) + screen->print("Sent ad-hoc position\n"); + else + screen->print("Sent ad-hoc nodeinfo\n"); + screen->forceDisplay(true); // Force a new UI frame, then force an EInk update + } + clickCount = 0; + } + } else { + clickCount = 1; + } + + lastClickTime = currentTime; // Update last click time + } + } + // Reset the touch status + is_touching = false; + } + // You can add more status checks, such as sliding and dragging + if (t.wasFlickStart()) { + LOG_INFO("Flick Start Detected\n"); + M5.Speaker.tone(1000, 100); + powerFSM.trigger(EVENT_PRESS); + } + } +} +#endif \ No newline at end of file diff --git a/src/ButtonThread.h b/src/ButtonThread.h index 9cd7b3dac3..4f1507af4a 100644 --- a/src/ButtonThread.h +++ b/src/ButtonThread.h @@ -66,3 +66,7 @@ class ButtonThread : public concurrency::OSThread }; extern ButtonThread *buttonThread; + +#if defined(M5STACK_CORE2) +void ScreenTouch(); +#endif \ No newline at end of file diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index bd0133740c..ed4db6f0dc 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -66,6 +66,15 @@ along with this program. If not, see . #include "platform/portduino/PortduinoGlue.h" #endif +#if defined(M5STACK_CORE2) +#include "M5Unified.h" +#define OLED_BLACK OLEDDISPLAY_COLOR::BLACK +#define OLED_WHITE OLEDDISPLAY_COLOR::WHITE +#else +#define OLED_BLACK BLACK +#define OLED_WHITE WHITE +#endif + using namespace meshtastic; /** @todo remove */ namespace graphics @@ -1571,6 +1580,10 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) pinMode(VTFT_LEDA, OUTPUT); digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); #endif +#endif +#if defined(M5STACK_CORE2) + M5.Power.Axp192.setDCDC3(1000); + M5.Display.setBrightness(130); #endif enabled = true; setInterval(0); // Draw ASAP @@ -1583,6 +1596,9 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif LOG_INFO("Turn off screen"); dispdev->displayOff(); +#if defined(M5STACK_CORE2) + M5.Power.Axp192.setDCDC3(0); +#endif #ifdef USE_ST7789 SPI1.end(); #if defined(ARCH_ESP32) @@ -2747,4 +2763,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN \ No newline at end of file +#endif // HAS_SCREEN diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 87c3f7de9f..7d76f6d06b 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -327,8 +327,10 @@ class LGFX : public lgfx::LGFX_Device { auto cfg = _light_instance.config(); // Gets a structure for backlight settings. - cfg.pin_bl = TFT_BL; // Pin number to which the backlight is connected - cfg.invert = false; // true to invert the brightness of the backlight +#if !defined(M5STACK_CORE2) + cfg.pin_bl = TFT_BL; // Pin number to which the backlight is connected +#endif + cfg.invert = false; // true to invert the brightness of the backlight // cfg.freq = 44100; // PWM frequency of backlight // cfg.pwm_channel = 1; // PWM channel number to use @@ -718,7 +720,7 @@ void TFTDisplay::sendCommand(uint8_t com) display(true); if (settingsMap[displayBacklight] > 0) digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON); -#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE) +#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE) && !defined(M5STACK_CORE2) tft->wakeup(); tft->powerSaveOff(); #endif @@ -730,7 +732,8 @@ void TFTDisplay::sendCommand(uint8_t com) unphone.backlight(true); // using unPhone library #endif #ifdef RAK14014 -#elif !defined(M5STACK) && !defined(ST7789_CS) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function +#elif !defined(M5STACK) && !defined(ST7789_CS) && \ + !defined(M5STACK_CORE2) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function tft->setBrightness(172); #endif break; @@ -837,9 +840,11 @@ bool TFTDisplay::connect() unphone.backlight(true); // using unPhone library #endif +#if !defined(M5STACK_CORE2) tft->init(); +#endif -#if defined(M5STACK) +#if defined(M5STACK) || defined(M5STACK_CORE2) tft->setRotation(0); #elif defined(RAK14014) tft->setRotation(1); @@ -860,4 +865,4 @@ bool TFTDisplay::connect() return true; } -#endif +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 97a64a378d..3165364407 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -117,6 +117,10 @@ AudioThread *audioThread = nullptr; float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if TCXO is optional, put this here so it can be changed further down. #endif +#if defined(M5STACK_CORE2) +#include +#endif + using namespace concurrency; volatile static const char slipstreamTZString[] = USERPREFS_TZ_STRING; @@ -804,6 +808,10 @@ void setup() RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_AXP192); // Record a hardware fault for missing hardware #endif +#if defined(M5STACK_CORE2) + M5.begin(); +#endif + #if !MESHTASTIC_EXCLUDE_I2C // Don't call screen setup until after nodedb is setup (because we need // the current region name) diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 1a274aa28d..408a19f010 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -104,6 +104,8 @@ #define HW_VENDOR meshtastic_HardwareModel_NANO_G1 #elif defined(M5STACK) #define HW_VENDOR meshtastic_HardwareModel_M5STACK +#elif defined(M5STACK_CORE2) +#define HW_VENDOR meshtastic_HardwareModel_M5STACK_CORE2 #elif defined(M5STACK_CORES3) #define HW_VENDOR meshtastic_HardwareModel_M5STACK_CORES3 #elif defined(STATION_G1) diff --git a/variants/m5stack_core2/pins_arduino.h b/variants/m5stack_core2/pins_arduino.h new file mode 100644 index 0000000000..86c6b812ab --- /dev/null +++ b/variants/m5stack_core2/pins_arduino.h @@ -0,0 +1,47 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t TX = 1; +static const uint8_t RX = 3; + +static const uint8_t TXD2 = 17; +static const uint8_t RXD2 = 16; + +static const uint8_t SDA = 21; +static const uint8_t SCL = 22; + +static const uint8_t SS = 33; +static const uint8_t MOSI = 23; +static const uint8_t MISO = 38; +static const uint8_t SCK = 18; + +static const uint8_t G23 = 23; +static const uint8_t G19 = 19; +static const uint8_t G18 = 18; +static const uint8_t G3 = 3; +static const uint8_t G16 = 16; +static const uint8_t G21 = 21; +static const uint8_t G2 = 2; +static const uint8_t G12 = 12; +static const uint8_t G15 = 15; +static const uint8_t G35 = 35; +static const uint8_t G36 = 36; +static const uint8_t G25 = 25; +static const uint8_t G26 = 26; +static const uint8_t G1 = 1; +static const uint8_t G17 = 17; +static const uint8_t G22 = 22; +static const uint8_t G5 = 5; +static const uint8_t G13 = 13; +static const uint8_t G0 = 0; +static const uint8_t G34 = 34; + +static const uint8_t DAC1 = 25; +static const uint8_t DAC2 = 26; + +static const uint8_t ADC1 = 35; +static const uint8_t ADC2 = 36; + +#endif /* Pins_Arduino_h */ diff --git a/variants/m5stack_core2/platformio.ini b/variants/m5stack_core2/platformio.ini new file mode 100644 index 0000000000..eb98c01234 --- /dev/null +++ b/variants/m5stack_core2/platformio.ini @@ -0,0 +1,26 @@ +[env:m5stack-core2] +extends = esp32_base +board = m5stack-core-esp32 +monitor_filters = esp32_exception_decoder +build_src_filter = + ${esp32_base.build_src_filter} +build_flags = + ${esp32_base.build_flags} -I variants/m5stack_core2 + -DILI9341_DRIVER + -DM5STACK_CORE2 + -DUSER_SETUP_LOADED + -DTFT_SDA_READ + -DTFT_DRIVER=0x9341 + -DTFT_MISO=38 + -DTFT_MOSI=23 + -DTFT_SCLK=18 + -DTFT_CS=5 + -DTFT_DC=15 + -DTFT_RST=-1 + -DSPI_FREQUENCY=40000000 + -DSPI_READ_FREQUENCY=16000000 + -DDISABLE_ALL_LIBRARY_WARNINGS +lib_deps = + ${esp32_base.lib_deps} + lovyan03/LovyanGFX@^1.1.16 + m5stack/M5Unified@^0.2.0 diff --git a/variants/m5stack_core2/variant.h b/variants/m5stack_core2/variant.h new file mode 100644 index 0000000000..2a07611f9f --- /dev/null +++ b/variants/m5stack_core2/variant.h @@ -0,0 +1,40 @@ +#define BUTTON_NEED_PULLUP +#define HAS_AXP192 +#define I2C_SDA 21 // For AXP192 +#define I2C_SCL 22 // For AXP192 + +#undef LORA_SCK +#undef LORA_MISO +#undef LORA_MOSI +#undef LORA_CS + +#define LORA_SCK 18 +#define LORA_MISO 38 +#define LORA_MOSI 23 +#define LORA_CS 27 // NSS + +#define USE_RF95 +#define LORA_DIO0 35 // IRQ +#define LORA_RESET 25 +#define LORA_DIO1 RADIOLIB_NC // Not really used +#define LORA_DIO2 RADIOLIB_NC // Not really used + +// This board has different GPS pins than all other boards +#undef GPS_RX_PIN +#undef GPS_TX_PIN +//#define GPS_RX_PIN 13 +//#define GPS_TX_PIN 14 + +#define TFT_HEIGHT 240 +#define TFT_WIDTH 320 +#define TFT_OFFSET_X 0 +#define TFT_OFFSET_Y 0 +#define TFT_BUSY -1 +#define TFT_OFFSET_ROTATION 0 + +// LCD screens are slow, so slowdown the wipe so it looks better +#define SCREEN_TRANSITION_FRAMERATE 30 // fps + +// M5Stack Core2 gets a white on black display +#define TFT_MESH COLOR565(0xA0, 0xFF, 0x00) //(0x94, 0xEA, 0x67) +#define ILI9341_SPI_HOST VSPI_HOST // VSPI_HOST or HSPI_HOST