Merge branch 'dev' into dev-meshpocket

This commit is contained in:
Quency-D 2025-09-04 11:47:55 +08:00 committed by GitHub
commit 13d046892a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 354 additions and 150 deletions

View file

@ -85,8 +85,7 @@ public:
}
void powerOff() override {
// TODO: re-enable this when there is a definite wake-up source pin:
// enterDeepSleep(0);
enterDeepSleep(0);
}
uint16_t getBattMilliVolts() override {

View file

@ -16,6 +16,7 @@ bool GxEPDDisplay::begin() {
display.fillScreen(GxEPD_WHITE);
display.display(true);
#if DISP_BACKLIGHT
digitalWrite(DISP_BACKLIGHT, LOW);
pinMode(DISP_BACKLIGHT, OUTPUT);
#endif
_init = true;
@ -24,14 +25,14 @@ bool GxEPDDisplay::begin() {
void GxEPDDisplay::turnOn() {
if (!_init) begin();
#if DISP_BACKLIGHT
#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN)
digitalWrite(DISP_BACKLIGHT, HIGH);
#endif
_isOn = true;
}
void GxEPDDisplay::turnOff() {
#if DISP_BACKLIGHT
#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN)
digitalWrite(DISP_BACKLIGHT, LOW);
#endif
_isOn = false;
@ -40,14 +41,17 @@ void GxEPDDisplay::turnOff() {
void GxEPDDisplay::clear() {
display.fillScreen(GxEPD_WHITE);
display.setTextColor(GxEPD_BLACK);
display_crc.reset();
}
void GxEPDDisplay::startFrame(Color bkg) {
display.fillScreen(GxEPD_WHITE);
display.setTextColor(_curr_color = GxEPD_BLACK);
display_crc.reset();
}
void GxEPDDisplay::setTextSize(int sz) {
display_crc.update<int>(sz);
switch(sz) {
case 1: // Small
display.setFont(&FreeSans9pt7b);
@ -65,6 +69,7 @@ void GxEPDDisplay::setTextSize(int sz) {
}
void GxEPDDisplay::setColor(Color c) {
display_crc.update<Color> (c);
// colours need to be inverted for epaper displays
if (c == DARK) {
display.setTextColor(_curr_color = GxEPD_WHITE);
@ -74,22 +79,38 @@ void GxEPDDisplay::setColor(Color c) {
}
void GxEPDDisplay::setCursor(int x, int y) {
display_crc.update<int>(x);
display_crc.update<int>(y);
display.setCursor((x+offset_x)*scale_x, (y+offset_y)*scale_y);
}
void GxEPDDisplay::print(const char* str) {
display_crc.update<char>(str, strlen(str));
display.print(str);
}
void GxEPDDisplay::fillRect(int x, int y, int w, int h) {
display.fillRect(x*scale_x, y*scale_y, w*scale_x, h*scale_y, _curr_color);
display_crc.update<int>(x);
display_crc.update<int>(y);
display_crc.update<int>(w);
display_crc.update<int>(h);
display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
}
void GxEPDDisplay::drawRect(int x, int y, int w, int h) {
display.drawRect(x*scale_x, y*scale_y, w*scale_x, h*scale_y, _curr_color);
display_crc.update<int>(x);
display_crc.update<int>(y);
display_crc.update<int>(w);
display_crc.update<int>(h);
display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
}
void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
display_crc.update<int>(x);
display_crc.update<int>(y);
display_crc.update<int>(w);
display_crc.update<int>(h);
display_crc.update<uint8_t>(bits, w * h / 8);
// Calculate the base position in display coordinates
uint16_t startX = x * scale_x;
uint16_t startY = y * scale_y;
@ -133,5 +154,9 @@ uint16_t GxEPDDisplay::getTextWidth(const char* str) {
}
void GxEPDDisplay::endFrame() {
display.display(true);
uint32_t crc = display_crc.finalize();
if (crc != last_display_crc_value) {
display.display(true);
last_display_crc_value = crc;
}
}

View file

@ -15,6 +15,8 @@
#include <epd/GxEPD2_150_BN.h> // 1.54" b/w
#include <epd/GxEPD2_213_B74.h> // 2.13" b/w
#include <CRC32.h>
#include "DisplayDriver.h"
//GxEPD2_BW<GxEPD2_150_BN, 200> display(GxEPD2_150_BN(DISP_CS, DISP_DC, DISP_RST, DISP_BUSY)); // DEPG0150BN 200x200, SSD1681, TTGO T5 V2.4.1
@ -38,6 +40,8 @@ class GxEPDDisplay : public DisplayDriver {
bool _init = false;
bool _isOn = false;
uint16_t _curr_color;
CRC32 display_crc;
int last_display_crc_value = 0;
public:
// there is a margin in y...

View file

@ -1,5 +1,7 @@
#include "MomentaryButton.h"
#define MULTI_CLICK_WINDOW_MS 280
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup) {
_pin = pin;
_reverse = reverse;
@ -9,6 +11,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse
cancel = 0;
_long_millis = long_press_millis;
_threshold = 0;
_click_count = 0;
_last_click_time = 0;
_multi_click_window = MULTI_CLICK_WINDOW_MS;
_pending_click = false;
}
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_threshold) {
@ -20,6 +26,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_t
cancel = 0;
_long_millis = long_press_millis;
_threshold = analog_threshold;
_click_count = 0;
_last_click_time = 0;
_multi_click_window = MULTI_CLICK_WINDOW_MS;
_pending_click = false;
}
void MomentaryButton::begin() {
@ -35,6 +45,10 @@ bool MomentaryButton::isPressed() const {
void MomentaryButton::cancelClick() {
cancel = 1;
down_at = 0;
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
}
bool MomentaryButton::isPressed(int level) const {
@ -60,13 +74,20 @@ int MomentaryButton::check(bool repeat_click) {
// button UP
if (_long_millis > 0) {
if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis
event = BUTTON_EVENT_CLICK;
_click_count++;
_last_click_time = millis();
_pending_click = true;
}
} else {
event = BUTTON_EVENT_CLICK; // any UP results in CLICK event when NOT using long_press feature
_click_count++;
_last_click_time = millis();
_pending_click = true;
}
if (event == BUTTON_EVENT_CLICK && cancel) {
event = BUTTON_EVENT_NONE;
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
}
down_at = 0;
}
@ -77,8 +98,16 @@ int MomentaryButton::check(bool repeat_click) {
}
if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) {
event = BUTTON_EVENT_LONG_PRESS;
down_at = 0;
if (_pending_click) {
// long press during multi-click detection - cancel pending clicks
cancelClick();
} else {
event = BUTTON_EVENT_LONG_PRESS;
down_at = 0;
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
}
}
if (down_at > 0 && repeat_click) {
unsigned long diff = (unsigned long)(millis() - down_at);
@ -87,5 +116,30 @@ int MomentaryButton::check(bool repeat_click) {
}
}
if (_pending_click && (millis() - _last_click_time) >= _multi_click_window) {
if (down_at > 0) {
// still pressed - wait for button release before processing clicks
return event;
}
switch (_click_count) {
case 1:
event = BUTTON_EVENT_CLICK;
break;
case 2:
event = BUTTON_EVENT_DOUBLE_CLICK;
break;
case 3:
event = BUTTON_EVENT_TRIPLE_CLICK;
break;
default:
// For 4+ clicks, treat as triple click?
event = BUTTON_EVENT_TRIPLE_CLICK;
break;
}
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
}
return event;
}

View file

@ -5,6 +5,8 @@
#define BUTTON_EVENT_NONE 0
#define BUTTON_EVENT_CLICK 1
#define BUTTON_EVENT_LONG_PRESS 2
#define BUTTON_EVENT_DOUBLE_CLICK 3
#define BUTTON_EVENT_TRIPLE_CLICK 4
class MomentaryButton {
int8_t _pin;
@ -13,6 +15,10 @@ class MomentaryButton {
int _long_millis;
int _threshold; // analog mode
unsigned long down_at;
uint8_t _click_count;
unsigned long _last_click_time;
int _multi_click_window;
bool _pending_click;
bool isPressed(int level) const;

View file

@ -2,13 +2,17 @@
#include "DisplayDriver.h"
#define KEY_LEFT 0xB4
#define KEY_UP 0xB5
#define KEY_DOWN 0xB6
#define KEY_RIGHT 0xB7
#define KEY_SELECT 10
#define KEY_ENTER 13
#define KEY_BACK 27 // Esc
#define KEY_LEFT 0xB4
#define KEY_UP 0xB5
#define KEY_DOWN 0xB6
#define KEY_RIGHT 0xB7
#define KEY_SELECT 10
#define KEY_ENTER 13
#define KEY_CANCEL 27 // Esc
#define KEY_HOME 0xF0
#define KEY_NEXT 0xF1
#define KEY_PREV 0xF2
#define KEY_CONTEXT_MENU 0xF3
class UIScreen {
protected: