mirror of
https://github.com/pelgraine/Meck.git
synced 2026-08-10 10:42:42 +02:00
t5s3 ui fixes; t5s3 initial ble and wifi companion build envs
This commit is contained in:
@@ -1101,9 +1101,9 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// T-Deck Pro: BLE starts disabled for standalone-first operation
|
||||
// User can toggle it on from the Bluetooth home page (Enter or long-press)
|
||||
#if defined(LilyGo_TDeck_Pro) && defined(BLE_PIN_CODE)
|
||||
// BLE starts disabled for standalone-first operation
|
||||
// User can toggle it from the Bluetooth home page (Enter or long-press)
|
||||
#if (defined(LilyGo_TDeck_Pro) || defined(LilyGo_T5S3_EPaper_Pro)) && defined(BLE_PIN_CODE)
|
||||
serial_interface.disable();
|
||||
MESH_DEBUG_PRINTLN("setup() - BLE disabled at boot (standalone mode)");
|
||||
#endif
|
||||
|
||||
@@ -811,7 +811,9 @@ public:
|
||||
if (wb == ' ' || isEmojiEscape(wb)) break;
|
||||
charStr[0] = (char)wb;
|
||||
dblStr[0] = dblStr[1] = (char)wb;
|
||||
wordW += display.getTextWidth(dblStr) - display.getTextWidth(charStr);
|
||||
int charAdv = display.getTextWidth(dblStr) - display.getTextWidth(charStr);
|
||||
if (charAdv < 1) charAdv = 1;
|
||||
wordW += charAdv;
|
||||
}
|
||||
if (px + wordW > lineW) {
|
||||
px = 0;
|
||||
@@ -840,6 +842,7 @@ public:
|
||||
charStr[0] = ' ';
|
||||
dblStr[0] = dblStr[1] = ' ';
|
||||
int adv = display.getTextWidth(dblStr) - display.getTextWidth(charStr);
|
||||
if (adv < 1) adv = 1; // Minimum advance (rounding fix for proportional fonts)
|
||||
if (px + adv > lineW) {
|
||||
px = 0;
|
||||
linesForThisMsg++;
|
||||
@@ -857,6 +860,7 @@ public:
|
||||
charStr[0] = (char)b;
|
||||
dblStr[0] = dblStr[1] = (char)b;
|
||||
int adv = display.getTextWidth(dblStr) - display.getTextWidth(charStr);
|
||||
if (adv < 1) adv = 1; // Minimum advance (rounding fix for proportional fonts)
|
||||
if (px + adv > lineW) {
|
||||
px = 0;
|
||||
linesForThisMsg++;
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
#include <MeshCore.h>
|
||||
#include "../NodePrefs.h"
|
||||
|
||||
// Inline edit hint shown next to values being adjusted
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
#define EDIT_ADJ_HINT "<Swipe>"
|
||||
#else
|
||||
#define EDIT_ADJ_HINT "<W/S>"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_4G_MODEM
|
||||
#include "ModemManager.h"
|
||||
#endif
|
||||
@@ -640,7 +647,7 @@ public:
|
||||
|
||||
case ROW_BW:
|
||||
if (editing && _editMode == EDIT_NUMBER) {
|
||||
snprintf(tmp, sizeof(tmp), "BW: %.1f <W/S>", _editFloat);
|
||||
snprintf(tmp, sizeof(tmp), "BW: %.1f " EDIT_ADJ_HINT, _editFloat);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "BW: %.1f kHz", _prefs->bw);
|
||||
}
|
||||
@@ -649,7 +656,7 @@ public:
|
||||
|
||||
case ROW_SF:
|
||||
if (editing && _editMode == EDIT_NUMBER) {
|
||||
snprintf(tmp, sizeof(tmp), "SF: %d <W/S>", _editInt);
|
||||
snprintf(tmp, sizeof(tmp), "SF: %d " EDIT_ADJ_HINT, _editInt);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "SF: %d", _prefs->sf);
|
||||
}
|
||||
@@ -658,7 +665,7 @@ public:
|
||||
|
||||
case ROW_CR:
|
||||
if (editing && _editMode == EDIT_NUMBER) {
|
||||
snprintf(tmp, sizeof(tmp), "CR: %d <W/S>", _editInt);
|
||||
snprintf(tmp, sizeof(tmp), "CR: %d " EDIT_ADJ_HINT, _editInt);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "CR: %d", _prefs->cr);
|
||||
}
|
||||
@@ -667,7 +674,7 @@ public:
|
||||
|
||||
case ROW_TX_POWER:
|
||||
if (editing && _editMode == EDIT_NUMBER) {
|
||||
snprintf(tmp, sizeof(tmp), "TX: %d dBm <W/S>", _editInt);
|
||||
snprintf(tmp, sizeof(tmp), "TX: %d dBm " EDIT_ADJ_HINT, _editInt);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "TX: %d dBm", _prefs->tx_power_dbm);
|
||||
}
|
||||
@@ -676,7 +683,7 @@ public:
|
||||
|
||||
case ROW_UTC_OFFSET:
|
||||
if (editing && _editMode == EDIT_NUMBER) {
|
||||
snprintf(tmp, sizeof(tmp), "UTC: %+d <W/S>", _editInt);
|
||||
snprintf(tmp, sizeof(tmp), "UTC: %+d " EDIT_ADJ_HINT, _editInt);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "UTC Offset: %+d", _prefs->utc_offset_hours);
|
||||
}
|
||||
@@ -691,7 +698,7 @@ public:
|
||||
|
||||
case ROW_PATH_HASH_SIZE:
|
||||
if (editing && _editMode == EDIT_NUMBER) {
|
||||
snprintf(tmp, sizeof(tmp), "Path Hash Size: %d-byte <W/S>", _editInt);
|
||||
snprintf(tmp, sizeof(tmp), "Path Hash Size: %d-byte " EDIT_ADJ_HINT, _editInt);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "Path Hash Size: %d-byte", _prefs->path_hash_mode + 1);
|
||||
}
|
||||
@@ -1002,8 +1009,22 @@ public:
|
||||
display.setTextSize(0);
|
||||
if (_editMode == EDIT_NONE) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Select Hold: Edit Boot: Home");
|
||||
} else if (_editMode == EDIT_NUMBER) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe Up/Down: Adjust Tap: OK Boot: Cancel");
|
||||
} else if (_editMode == EDIT_PICKER) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe Left/Right: Choose Tap: OK");
|
||||
} else if (_editMode == EDIT_CONFIRM) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Tap: Confirm Boot: Cancel");
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
} else if (_editMode == EDIT_WIFI) {
|
||||
if (_wifiPhase == WIFI_PHASE_SELECT) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Pick Tap: Select Boot: Back");
|
||||
} else {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Please wait...");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
display.print("Editing...");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Editing...");
|
||||
}
|
||||
#else
|
||||
if (_editMode == EDIT_TEXT) {
|
||||
|
||||
@@ -1058,16 +1058,18 @@ public:
|
||||
}
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
// FreeSans12pt is proportional — "M" is the widest character.
|
||||
// Using M-width gives ~56 chars/line but actual text only fills 60% of screen.
|
||||
// Re-measure with representative lowercase text for realistic average width.
|
||||
// Re-measure with representative lowercase text, then apply 1.5× multiplier
|
||||
// because real English text averages much narrower than the sample string.
|
||||
// With proportional fonts, character-count-based wrapping is inherently
|
||||
// approximate — some lines will be shorter, but none should overflow.
|
||||
{
|
||||
uint16_t sampleW = display.getTextWidth("abcdefghijklmno"); // 15 chars
|
||||
if (sampleW > 0) {
|
||||
_charsPerLine = (display.width() * 15) / sampleW;
|
||||
_charsPerLine = (display.width() * 15 * 3) / (sampleW * 2); // ×1.5
|
||||
}
|
||||
}
|
||||
if (_charsPerLine < 15) _charsPerLine = 15;
|
||||
if (_charsPerLine > 120) _charsPerLine = 120; // Proportional fonts can fit many chars
|
||||
if (_charsPerLine > 120) _charsPerLine = 120;
|
||||
#else
|
||||
if (_charsPerLine < 15) _charsPerLine = 15;
|
||||
if (_charsPerLine > 60) _charsPerLine = 60;
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#if UI_HAS_JOYSTICK
|
||||
#define PRESS_LABEL "press Enter"
|
||||
#elif defined(LilyGo_T5S3_EPaper_Pro)
|
||||
#define PRESS_LABEL "hold Boot btn"
|
||||
#else
|
||||
#define PRESS_LABEL "long press"
|
||||
#endif
|
||||
@@ -156,7 +158,11 @@ void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts,
|
||||
// layout: [icon 16px][cap 2px][gap 2px][text][margin 2px]
|
||||
int totalWidth = iconWidth + 2 + 2 + textWidth + 2;
|
||||
int iconX = display.width() - totalWidth;
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
int iconY = 4; // Shift down to match header text offset
|
||||
#else
|
||||
int iconY = 0; // vertically align with node name text
|
||||
#endif
|
||||
|
||||
if (outIconX) *outIconX = iconX;
|
||||
|
||||
@@ -253,7 +259,14 @@ public:
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
char filtered_name[sizeof(_node_prefs->node_name)];
|
||||
display.translateUTF8ToBlocks(filtered_name, _node_prefs->node_name, sizeof(filtered_name));
|
||||
display.setCursor(0, -3);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
// T5S3: FreeSans12pt ascenders need more room than built-in font.
|
||||
// Shift header elements down by 4 virtual units (~17px physical).
|
||||
#define HOME_HDR_Y 1
|
||||
#else
|
||||
#define HOME_HDR_Y -3
|
||||
#endif
|
||||
display.setCursor(0, HOME_HDR_Y);
|
||||
display.print(filtered_name);
|
||||
|
||||
// battery voltage
|
||||
@@ -285,13 +298,17 @@ public:
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
uint16_t tw = display.getTextWidth(timeBuf);
|
||||
int clockX = (display.width() - tw) / 2;
|
||||
display.setCursor(clockX, -3); // align with battery text Y
|
||||
display.setCursor(clockX, HOME_HDR_Y); // align with node name Y
|
||||
display.print(timeBuf);
|
||||
display.setTextSize(1); // restore
|
||||
}
|
||||
}
|
||||
// curr page indicator
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
int y = 18;
|
||||
#else
|
||||
int y = 14;
|
||||
#endif
|
||||
int x = display.width() / 2 - 5 * (HomePage::Count-1);
|
||||
for (uint8_t i = 0; i < HomePage::Count; i++, x += 10) {
|
||||
if (i == _page) {
|
||||
@@ -305,7 +322,11 @@ public:
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
_task->setHomeShowingTiles(true);
|
||||
#endif
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
int y = 24;
|
||||
#else
|
||||
int y = 20;
|
||||
#endif
|
||||
display.setColor(DisplayDriver::YELLOW);
|
||||
display.setTextSize(2);
|
||||
sprintf(tmp, "MSG: %d", _task->getUnreadMsgCount());
|
||||
@@ -1093,10 +1114,9 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
|
||||
((ChannelScreen *) channel_screen)->markChannelRead(channel_idx);
|
||||
}
|
||||
|
||||
#if defined(LilyGo_TDeck_Pro)
|
||||
// T-Deck Pro: Don't interrupt user with popup - just show brief notification
|
||||
// Messages are stored in channel history, accessible via 'M' key
|
||||
// Suppress alert entirely on admin screen - it needs focused interaction
|
||||
#if defined(LilyGo_TDeck_Pro) || defined(LilyGo_T5S3_EPaper_Pro)
|
||||
// Don't interrupt user with popup - just show brief notification
|
||||
// Messages are stored in channel history, accessible via tile/key
|
||||
if (!isOnRepeaterAdmin()) {
|
||||
char alertBuf[40];
|
||||
snprintf(alertBuf, sizeof(alertBuf), "New: %s", from_name);
|
||||
@@ -1470,7 +1490,7 @@ char UITask::handleTripleClick(char c) {
|
||||
if (board.isBacklightOn()) {
|
||||
board.setBacklight(false); // If already on, turn off
|
||||
} else {
|
||||
board.setBacklightBrightness(4);
|
||||
board.setBacklightBrightness(40);
|
||||
board.setBacklight(true);
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -94,55 +94,69 @@ lib_deps =
|
||||
https://github.com/lewisxhe/SensorLib/archive/refs/tags/v0.3.4.zip
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Phase 3+ variants (uncomment when touch input is implemented)
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
; T5S3 BLE companion — touch UI, BLE phone bridging
|
||||
;[env:meck_t5s3_ble]
|
||||
;extends = LilyGo_T5S3_EPaper_Pro
|
||||
;build_flags =
|
||||
; ${LilyGo_T5S3_EPaper_Pro.build_flags}
|
||||
; -I examples/companion_radio/ui-new
|
||||
; -D MAX_CONTACTS=500
|
||||
; -D MAX_GROUP_CHANNELS=20
|
||||
; -D BLE_PIN_CODE=123456
|
||||
; -D OFFLINE_QUEUE_SIZE=256
|
||||
; -D DISPLAY_CLASS=FastEPDDisplay
|
||||
; -D USE_EINK
|
||||
; -D MECK_WEB_READER=1
|
||||
;build_src_filter = ${LilyGo_T5S3_EPaper_Pro.build_src_filter}
|
||||
; +<helpers/esp32/*.cpp>
|
||||
; +<helpers/ui/MomentaryButton.cpp>
|
||||
; +<helpers/ui/FastEPDDisplay.cpp>
|
||||
; +<../examples/companion_radio/*.cpp>
|
||||
; +<../examples/companion_radio/ui-new/*.cpp>
|
||||
;lib_deps =
|
||||
; ${LilyGo_T5S3_EPaper_Pro.lib_deps}
|
||||
; densaugeo/base64 @ ~1.4.0
|
||||
; bitbank2/PNGdec@^1.0.1
|
||||
; adafruit/Adafruit GFX Library@^1.11.0
|
||||
; https://github.com/mverch67/FastEPD/archive/0df1bff329b6fc782e062f611758880762340647.zip
|
||||
; Connect via MeshCore iOS/Android app over Bluetooth
|
||||
; Flash: pio run -e meck_t5s3_ble -t upload
|
||||
; ---------------------------------------------------------------------------
|
||||
[env:meck_t5s3_ble]
|
||||
extends = LilyGo_T5S3_EPaper_Pro
|
||||
build_flags =
|
||||
${LilyGo_T5S3_EPaper_Pro.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=500
|
||||
-D MAX_GROUP_CHANNELS=20
|
||||
-D BLE_PIN_CODE=123456
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D DISPLAY_CLASS=FastEPDDisplay
|
||||
-D USE_EINK
|
||||
; -D MECK_SERIF_FONT
|
||||
build_src_filter = ${LilyGo_T5S3_EPaper_Pro.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<helpers/ui/FastEPDDisplay.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T5S3_EPaper_Pro.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
adafruit/Adafruit GFX Library@^1.11.0
|
||||
https://github.com/mverch67/FastEPD/archive/0df1bff329b6fc782e062f611758880762340647.zip
|
||||
https://github.com/lewisxhe/SensorLib/archive/refs/tags/v0.3.4.zip
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; T5S3 WiFi companion — touch UI, WiFi phone bridging
|
||||
; Connect via MeshCore web app or meshcore.js over local network (TCP:5000)
|
||||
; Flash: pio run -e meck_t5s3_wifi -t upload
|
||||
; ---------------------------------------------------------------------------
|
||||
[env:meck_t5s3_wifi]
|
||||
extends = LilyGo_T5S3_EPaper_Pro
|
||||
build_flags =
|
||||
${LilyGo_T5S3_EPaper_Pro.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=1500
|
||||
-D MAX_GROUP_CHANNELS=20
|
||||
-D MECK_WIFI_COMPANION=1
|
||||
-D TCP_PORT=5000
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D DISPLAY_CLASS=FastEPDDisplay
|
||||
-D USE_EINK
|
||||
; -D MECK_SERIF_FONT
|
||||
build_src_filter = ${LilyGo_T5S3_EPaper_Pro.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<helpers/ui/FastEPDDisplay.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T5S3_EPaper_Pro.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
adafruit/Adafruit GFX Library@^1.11.0
|
||||
https://github.com/mverch67/FastEPD/archive/0df1bff329b6fc782e062f611758880762340647.zip
|
||||
https://github.com/lewisxhe/SensorLib/archive/refs/tags/v0.3.4.zip
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; T5S3 standalone — touch UI, no BLE/WiFi, maximum battery life
|
||||
;[env:meck_t5s3_standalone]
|
||||
;extends = LilyGo_T5S3_EPaper_Pro
|
||||
;build_flags =
|
||||
; ${LilyGo_T5S3_EPaper_Pro.build_flags}
|
||||
; -I examples/companion_radio/ui-new
|
||||
; -D MAX_CONTACTS=1500
|
||||
; -D MAX_GROUP_CHANNELS=20
|
||||
; -D OFFLINE_QUEUE_SIZE=256
|
||||
; -D DISPLAY_CLASS=FastEPDDisplay
|
||||
; -D USE_EINK
|
||||
;build_src_filter = ${LilyGo_T5S3_EPaper_Pro.build_src_filter}
|
||||
; +<helpers/esp32/*.cpp>
|
||||
; +<helpers/ui/MomentaryButton.cpp>
|
||||
; +<helpers/ui/FastEPDDisplay.cpp>
|
||||
; +<../examples/companion_radio/*.cpp>
|
||||
; +<../examples/companion_radio/ui-new/*.cpp>
|
||||
;lib_deps =
|
||||
; ${LilyGo_T5S3_EPaper_Pro.lib_deps}
|
||||
; densaugeo/base64 @ ~1.4.0
|
||||
; bitbank2/PNGdec@^1.0.1
|
||||
; adafruit/Adafruit GFX Library@^1.11.0
|
||||
; https://github.com/mverch67/FastEPD/archive/0df1bff329b6fc782e062f611758880762340647.zip
|
||||
; (same as headless but explicitly named for clarity)
|
||||
; ---------------------------------------------------------------------------
|
||||
[env:meck_t5s3_standalone]
|
||||
extends = env:meck_t5s3_headless
|
||||
Reference in New Issue
Block a user