diff --git a/.gitmodules b/.gitmodules
index 7c54ad5139..964204476d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,9 @@
[submodule "protobufs"]
path = protobufs
url = https://github.com/meshtastic/protobufs.git
+[submodule "lib/device-ui"]
+ path = lib/device-ui
+ url = https://github.com/meshtastic/device-ui.git
[submodule "meshtestic"]
path = meshtestic
url = https://github.com/meshtastic/meshTestic
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index 1af68198bf..4e3093c558 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -24,4 +24,4 @@ lib_deps=
lib_ignore =
BluetoothOTA
- lvgl
+ lvgl
\ No newline at end of file
diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini
index c004a3becb..62b4ac30c8 100644
--- a/arch/rp2xx0/rp2040.ini
+++ b/arch/rp2xx0/rp2040.ini
@@ -18,6 +18,7 @@ build_src_filter =
lib_ignore =
BluetoothOTA
+ lvgl
lib_deps =
${arduino_base.lib_deps}
diff --git a/boards/mesh-tab.json b/boards/mesh-tab.json
new file mode 100644
index 0000000000..75ac1b5a21
--- /dev/null
+++ b/boards/mesh-tab.json
@@ -0,0 +1,42 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "esp32s3_out.ld",
+ "partitions": "default_16MB.csv",
+ "memory_type": "qio_qspi"
+ },
+ "core": "esp32",
+ "extra_flags": [
+ "-DBOARD_HAS_PSRAM",
+ "-DARDUINO_USB_CDC_ON_BOOT=1",
+ "-DARDUINO_USB_MODE=0",
+ "-DARDUINO_RUNNING_CORE=1",
+ "-DARDUINO_EVENT_RUNNING_CORE=1"
+ ],
+ "f_cpu": "240000000L",
+ "f_flash": "80000000L",
+ "flash_mode": "qio",
+ "hwids": [["0x303A", "0x1001"]],
+ "mcu": "esp32s3",
+ "variant": "mesh-tab"
+ },
+ "connectivity": ["wifi", "bluetooth", "lora"],
+ "debug": {
+ "default_tool": "esp-builtin",
+ "onboard_tools": ["esp-builtin"],
+ "openocd_target": "esp32s3.cfg"
+ },
+ "frameworks": ["arduino", "espidf"],
+ "name": "ESP32-S3 WROOM-1 N16R2 (16 MB FLASH, 2 MB PSRAM)",
+ "upload": {
+ "flash_size": "16MB",
+ "maximum_ram_size": 327680,
+ "maximum_size": 16777216,
+ "use_1200bps_touch": true,
+ "wait_for_upload_port": true,
+ "require_upload_port": true,
+ "speed": 460800
+ },
+ "url": "https://github.com/valzzu/Mesh-Tab",
+ "vendor": "Espressif"
+}
diff --git a/boards/seeed-sensecap-indicator.json b/boards/seeed-sensecap-indicator.json
index 3fc57126f9..6ce8d36adc 100644
--- a/boards/seeed-sensecap-indicator.json
+++ b/boards/seeed-sensecap-indicator.json
@@ -15,10 +15,12 @@
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
+ "f_boot": "120000000L",
+ "boot": "qio",
"flash_mode": "qio",
"hwids": [["0x1A86", "0x7523"]],
"mcu": "esp32s3",
- "variant": "esp32s3r8"
+ "variant": "esp32s3"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
diff --git a/boards/t-deck.json b/boards/t-deck.json
index d62ec48e65..b112921b9b 100644
--- a/boards/t-deck.json
+++ b/boards/t-deck.json
@@ -10,7 +10,7 @@
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
- "-DARDUINO_EVENT_RUNNING_CORE=0"
+ "-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
diff --git a/lib/device-ui b/lib/device-ui
new file mode 160000
index 0000000000..6b760f5373
--- /dev/null
+++ b/lib/device-ui
@@ -0,0 +1 @@
+Subproject commit 6b760f5373b91de1d8234922a446f7232d5247d0
diff --git a/src/configuration.h b/src/configuration.h
index cb2326470c..74b68e44f7 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -246,6 +246,9 @@ along with this program. If not, see .
#ifndef HAS_SCREEN
#define HAS_SCREEN 0
#endif
+#ifndef HAS_TFT
+#define HAS_TFT 0
+#endif
#ifndef HAS_WIRE
#define HAS_WIRE 0
#endif
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index d39c9899c5..19b32a1aab 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -490,4 +490,4 @@ size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index efa3ec78fe..f78549a2a6 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -1709,7 +1709,7 @@ void Screen::setup()
#endif
serialSinceMsec = millis();
-#if ARCH_PORTDUINO
+#if ARCH_PORTDUINO && !HAS_TFT
if (settingsMap[touchscreenModule]) {
touchScreenImpl1 =
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast(dispdev)->getTouch);
diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp
index 3ba847c236..986d081bdf 100644
--- a/src/graphics/TFTDisplay.cpp
+++ b/src/graphics/TFTDisplay.cpp
@@ -347,12 +347,12 @@ static LGFX *tft = nullptr;
#include // Graphics and font library for ILI9342 driver chip
static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
-#elif ARCH_PORTDUINO && HAS_SCREEN != 0
+#elif ARCH_PORTDUINO && HAS_SCREEN != 0 && !HAS_TFT
#include // Graphics and font library for ST7735 driver chip
class LGFX : public lgfx::LGFX_Device
{
- lgfx::Panel_LCD *_panel_instance;
+ lgfx::Panel_Device *_panel_instance;
lgfx::Bus_SPI _bus_instance;
lgfx::ITouch *_touch_instance;
@@ -366,10 +366,21 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance = new lgfx::Panel_ST7735;
else if (settingsMap[displayPanel] == st7735s)
_panel_instance = new lgfx::Panel_ST7735S;
+ else if (settingsMap[displayPanel] == st7796)
+ _panel_instance = new lgfx::Panel_ST7796;
else if (settingsMap[displayPanel] == ili9341)
_panel_instance = new lgfx::Panel_ILI9341;
else if (settingsMap[displayPanel] == ili9342)
_panel_instance = new lgfx::Panel_ILI9342;
+ else if (settingsMap[displayPanel] == ili9488)
+ _panel_instance = new lgfx::Panel_ILI9488;
+ else if (settingsMap[displayPanel] == hx8357d)
+ _panel_instance = new lgfx::Panel_HX8357D;
+ else {
+ _panel_instance = new lgfx::Panel_NULL;
+ LOG_ERROR("Unknown display panel configured!");
+ }
+
auto buscfg = _bus_instance.config();
buscfg.spi_mode = 0;
buscfg.spi_host = settingsMap[displayspidev];
@@ -383,12 +394,12 @@ class LGFX : public lgfx::LGFX_Device
LOG_DEBUG("Height: %d, Width: %d ", settingsMap[displayHeight], settingsMap[displayWidth]);
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
cfg.pin_rst = settingsMap[displayReset];
- cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
- cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
- cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction
- cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction
- cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
- cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed
+ cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
+ cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
+ cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction
+ cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction
+ cfg.offset_rotation = settingsMap[displayOffsetRotate]; // Rotation direction value offset 0~7 (4~7 is mirrored)
+ cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed
_panel_instance->config(cfg);
@@ -410,7 +421,7 @@ class LGFX : public lgfx::LGFX_Device
touch_cfg.y_max = settingsMap[displayWidth] - 1;
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
touch_cfg.bus_shared = true;
- touch_cfg.offset_rotation = 1;
+ touch_cfg.offset_rotation = settingsMap[touchscreenRotate];
if (settingsMap[touchscreenI2CAddr] != -1) {
touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr];
} else {
diff --git a/src/main.cpp b/src/main.cpp
index 0ce6b3bae6..db1b205ad4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -41,6 +41,7 @@
#include
#ifdef ARCH_ESP32
+#include "freertosinc.h"
#if !MESHTASTIC_EXCLUDE_WEBSERVER
#include "mesh/http/WebServer.h"
#endif
@@ -113,6 +114,18 @@ AccelerometerThread *accelerometerThread = nullptr;
AudioThread *audioThread = nullptr;
#endif
+#if HAS_TFT
+#include "DeviceScreen.h"
+#include "DisplayDriverConfig.h"
+#include "PacketClient.h"
+#include "PacketServer.h"
+#include "api/PacketAPI.h"
+
+void tft_task_handler(void *);
+
+DeviceScreen *deviceScreen = nullptr;
+#endif
+
#if defined(TCXO_OPTIONAL)
float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if TCXO is optional, put this here so it can be changed further down.
#endif
@@ -177,6 +190,8 @@ std::pair nodeTelemetrySensorsMap[_meshtastic_TelemetrySenso
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
+const char *firmware_version = optstr(APP_VERSION_SHORT);
+
const char *getDeviceName()
{
uint8_t dmac[6];
@@ -279,6 +294,7 @@ void setup()
#endif
powerMonInit();
+
serialSinceMsec = millis();
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n");
@@ -414,13 +430,13 @@ void setup()
digitalWrite(AQ_SET_PIN, HIGH);
#endif
-#ifdef T_DECK
+#if defined(T_DECK)
// enable keyboard
pinMode(KB_POWERON, OUTPUT);
digitalWrite(KB_POWERON, HIGH);
// There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time
// otherwise keyboard and touch screen will not work
- delay(800);
+ delay(200);
#endif
// Currently only the tbeam has a PMU
@@ -594,7 +610,6 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
- SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22)
@@ -733,11 +748,92 @@ void setup()
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
LOG_DEBUG("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
SPI.setFrequency(4000000);
+#endif
+#if HAS_TFT
+#ifdef PORTDUINO
+ if (settingsMap[displayPanel] != no_screen) {
+ DisplayDriverConfig displayConfig;
+ static char *panels[] = {"NOSCREEN", "X11", "ST7789", "ST7735", "ST7735S", "ST7796",
+ "ILI9341", "ILI9342", "ILI9486", "ILI9488", "HX8357D"};
+ static char *touch[] = {"NOTOUCH", "XPT2046", "STMPE610", "GT911", "FT5x06"};
+#ifdef USE_X11
+ if (settingsMap[displayPanel] == x11) {
+ if (settingsMap[displayWidth] && settingsMap[displayHeight])
+ displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::X11, (uint16_t)settingsMap[displayWidth],
+ (uint16_t)settingsMap[displayHeight]);
+ else
+ displayConfig.device(DisplayDriverConfig::device_t::X11);
+ } else
+#endif
+ {
+ displayConfig.device(DisplayDriverConfig::device_t::CUSTOM_TFT)
+ .panel(DisplayDriverConfig::panel_config_t{.type = panels[settingsMap[displayPanel]],
+ .panel_width = (uint16_t)settingsMap[displayWidth],
+ .panel_height = (uint16_t)settingsMap[displayHeight],
+ .rotation = (bool)settingsMap[displayRotate],
+ .pin_cs = (int16_t)settingsMap[displayCS],
+ .pin_rst = (int16_t)settingsMap[displayReset],
+ .offset_x = (uint16_t)settingsMap[displayOffsetX],
+ .offset_y = (uint16_t)settingsMap[displayOffsetY],
+ .offset_rotation = (uint8_t)settingsMap[displayOffsetRotate],
+ .invert = settingsMap[displayInvert] ? true : false,
+ .rgb_order = (bool)settingsMap[displayRGBOrder],
+ .dlen_16bit = settingsMap[displayPanel] == ili9486 ||
+ settingsMap[displayPanel] == ili9488})
+ .bus(DisplayDriverConfig::bus_config_t{.freq_write = (uint32_t)settingsMap[displayBusFrequency],
+ .freq_read = 16000000,
+ .spi{.pin_dc = (int8_t)settingsMap[displayDC],
+ .use_lock = true,
+ .spi_host = (uint16_t)settingsMap[displayspidev]}})
+ .input(DisplayDriverConfig::input_config_t{.keyboardDevice = settingsStrings[keyboardDevice],
+ .pointerDevice = settingsStrings[pointerDevice]})
+ .light(DisplayDriverConfig::light_config_t{.pin_bl = (int16_t)settingsMap[displayBacklight],
+ .pwm_channel = (int8_t)settingsMap[displayBacklightPWMChannel],
+ .invert = (bool)settingsMap[displayBacklightInvert]});
+ if (settingsMap[touchscreenI2CAddr] == -1) {
+ displayConfig.touch(
+ DisplayDriverConfig::touch_config_t{.type = touch[settingsMap[touchscreenModule]],
+ .freq = (uint32_t)settingsMap[touchscreenBusFrequency],
+ .pin_int = (int16_t)settingsMap[touchscreenIRQ],
+ .offset_rotation = (uint8_t)settingsMap[touchscreenRotate],
+ .spi{
+ .spi_host = (int8_t)settingsMap[touchscreenspidev],
+ },
+ .pin_cs = (int16_t)settingsMap[touchscreenCS]});
+ } else {
+ displayConfig.touch(DisplayDriverConfig::touch_config_t{
+ .type = touch[settingsMap[touchscreenModule]],
+ .freq = (uint32_t)settingsMap[touchscreenBusFrequency],
+ .x_min = 0,
+ .x_max =
+ (int16_t)((settingsMap[touchscreenRotate] & 1 ? settingsMap[displayWidth] : settingsMap[displayHeight]) -
+ 1),
+ .y_min = 0,
+ .y_max =
+ (int16_t)((settingsMap[touchscreenRotate] & 1 ? settingsMap[displayHeight] : settingsMap[displayWidth]) -
+ 1),
+ .pin_int = (int16_t)settingsMap[touchscreenIRQ],
+ .offset_rotation = (uint8_t)settingsMap[touchscreenRotate],
+ .i2c{.i2c_addr = (uint8_t)settingsMap[touchscreenI2CAddr]}});
+ }
+ }
+ deviceScreen = &DeviceScreen::create(&displayConfig);
+ PacketAPI::create(PacketServer::init());
+ deviceScreen->init(new PacketClient);
+ } else {
+ LOG_INFO("Running without TFT display!");
+ }
+#else
+ deviceScreen = &DeviceScreen::create();
+ PacketAPI::create(PacketServer::init());
+ deviceScreen->init(new PacketClient);
+#endif
#endif
// Initialize the screen first so we can show the logo while we start up everything else.
+#if HAS_SCREEN
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
-
+#endif
// setup TZ prior to time actions.
#if !MESHTASTIC_EXCLUDE_TZ
LOG_DEBUG("Using compiled/slipstreamed %s", slipstreamTZString); // important, removing this clobbers our magic string
@@ -1137,7 +1233,19 @@ void setup()
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
powerFSMthread = new PowerFSMThread();
+
+#if HAS_TFT
+#ifdef HAS_FREE_RTOS
+ xTaskCreatePinnedToCore(tft_task_handler, "tft", 8192, NULL, 1, NULL, 0);
+#endif
+#else
setCPUFast(false); // 80MHz is fine for our slow peripherals
+#endif
+
+#ifdef ARDUINO_ARCH_ESP32
+ LOG_DEBUG("Free heap : %7d bytes", ESP.getFreeHeap());
+ LOG_DEBUG("Free PSRAM : %7d bytes", ESP.getFreePsram());
+#endif
}
#endif
uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
@@ -1165,6 +1273,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
#endif
return deviceMetadata;
}
+
#ifndef PIO_UNIT_TESTING
void loop()
{
@@ -1196,3 +1305,22 @@ void loop()
}
}
#endif
+
+#if HAS_TFT
+void tft_task_handler(void *param = nullptr)
+{
+ while (true) {
+ if (deviceScreen) {
+ spiLock->lock();
+ deviceScreen->task_handler();
+ spiLock->unlock();
+ }
+#ifdef HAS_FREE_RTOS
+ vTaskDelay(5 / portTICK_PERIOD_MS);
+#else
+ delay(5);
+#endif
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 6b29919587..2bed40f008 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -58,6 +58,7 @@ NodeDB *nodeDB = nullptr;
EXT_RAM_BSS_ATTR meshtastic_DeviceState devicestate;
meshtastic_MyNodeInfo &myNodeInfo = devicestate.my_node;
meshtastic_LocalConfig config;
+meshtastic_DeviceUIConfig uiconfig{.screen_brightness = 153, .screen_timeout = 30};
meshtastic_LocalModuleConfig moduleConfig;
meshtastic_ChannelFile channelFile;
@@ -298,6 +299,13 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
rebootAtMsec = millis() + (5 * 1000);
}
+#if (defined(T_DECK) || defined(T_WATCH_S3) || defined(UNPHONE) || defined(PICOMPUTER_S3)) && defined(HAS_TFT)
+ // as long as PhoneAPI shares BT and TFT app switch BT off
+ config.bluetooth.enabled = false;
+ if (moduleConfig.external_notification.nag_timeout == 60)
+ moduleConfig.external_notification.nag_timeout = 0;
+#endif
+
return didFactoryReset;
}
@@ -748,6 +756,7 @@ void NodeDB::pickNewNodeNum()
static const char *prefFileName = "/prefs/db.proto";
static const char *configFileName = "/prefs/config.proto";
+static const char *uiconfigFileName = "/prefs/uiconfig.proto";
static const char *moduleConfigFileName = "/prefs/module.proto";
static const char *channelFileName = "/prefs/channels.proto";
@@ -850,6 +859,12 @@ void NodeDB::loadFromDisk()
}
}
+ state = loadProto(uiconfigFileName, meshtastic_DeviceUIConfig_size, sizeof(meshtastic_DeviceUIConfig),
+ &meshtastic_DeviceUIConfig_msg, &uiconfig);
+ if (state == LoadFileResult::LOAD_SUCCESS) {
+ LOG_INFO("Loaded UIConfig");
+ }
+
// 2.4.X - configuration migration to update new default intervals
if (moduleConfig.version < 23) {
LOG_DEBUG("ModuleConfig version %d is stale, upgrading to new default intervals", moduleConfig.version);
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index eb33a2f6d4..095e75500f 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -29,6 +29,7 @@ extern meshtastic_DeviceState devicestate;
extern meshtastic_ChannelFile channelFile;
extern meshtastic_MyNodeInfo &myNodeInfo;
extern meshtastic_LocalConfig config;
+extern meshtastic_DeviceUIConfig uiconfig;
extern meshtastic_LocalModuleConfig moduleConfig;
extern meshtastic_User &owner;
extern meshtastic_Position localPosition;
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index 98db38c47b..8a8838af1a 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -165,6 +165,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
*
* Our sending states progress in the following sequence (the client apps ASSUME THIS SEQUENCE, DO NOT CHANGE IT):
STATE_SEND_MY_INFO, // send our my info record
+ STATE_SEND_UIDATA,
STATE_SEND_OWN_NODEINFO,
STATE_SEND_METADATA,
STATE_SEND_CHANNELS
@@ -190,18 +191,24 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_NOTHING:
LOG_INFO("getFromRadio=STATE_SEND_NOTHING");
break;
-
case STATE_SEND_MY_INFO:
LOG_INFO("getFromRadio=STATE_SEND_MY_INFO");
// If the user has specified they don't want our node to share its location, make sure to tell the phone
// app not to send locations on our behalf.
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo;
- state = STATE_SEND_OWN_NODEINFO;
+ state = STATE_SEND_UIDATA;
service->refreshLocalMeshNode(); // Update my NodeInfo because the client will be asking for it soon.
break;
+ case STATE_SEND_UIDATA:
+ LOG_INFO("getFromRadio=STATE_SEND_UIDATA");
+ fromRadioScratch.which_payload_variant = meshtastic_FromRadio_deviceuiConfig_tag;
+ fromRadioScratch.deviceuiConfig = uiconfig;
+ state = STATE_SEND_OWN_NODEINFO;
+ break;
+
case STATE_SEND_OWN_NODEINFO: {
LOG_INFO("getFromRadio=STATE_SEND_OWN_NODEINFO");
auto us = nodeDB->readNextMeshNode(readIndex);
@@ -274,9 +281,12 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.config.which_payload_variant = meshtastic_Config_security_tag;
fromRadioScratch.config.payload_variant.security = config.security;
break;
- case meshtastic_Config_sessionkey_tag:
+ case meshtastic_Config_sessionkey_tag: // NOOP!
fromRadioScratch.config.which_payload_variant = meshtastic_Config_sessionkey_tag;
break;
+ case meshtastic_Config_device_ui_tag: // NOOP!
+ fromRadioScratch.config.which_payload_variant = meshtastic_Config_device_ui_tag;
+ break;
default:
LOG_ERROR("Unknown config type %d", config_state);
}
@@ -500,6 +510,7 @@ bool PhoneAPI::available()
case STATE_SEND_NOTHING:
return false;
case STATE_SEND_MY_INFO:
+ case STATE_SEND_UIDATA:
case STATE_SEND_CHANNELS:
case STATE_SEND_CONFIG:
case STATE_SEND_MODULECONFIG:
diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h
index 3247fee5c3..5b92d45d1b 100644
--- a/src/mesh/PhoneAPI.h
+++ b/src/mesh/PhoneAPI.h
@@ -34,6 +34,7 @@ class PhoneAPI
{
enum State {
STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config
+ STATE_SEND_UIDATA, // send stored data for device-ui
STATE_SEND_MY_INFO, // send our my info record
STATE_SEND_OWN_NODEINFO,
STATE_SEND_METADATA,
@@ -148,6 +149,9 @@ class PhoneAPI
*/
virtual void onNowHasData(uint32_t fromRadioNum) {}
+ /// begin a new connection
+ void handleStartConfig();
+
private:
void releasePhonePacket();
@@ -157,9 +161,6 @@ class PhoneAPI
void releaseClientNotification();
- /// begin a new connection
- void handleStartConfig();
-
bool wasSeenRecently(uint32_t packetId);
/**
diff --git a/src/mesh/api/PacketAPI.cpp b/src/mesh/api/PacketAPI.cpp
new file mode 100644
index 0000000000..6c3604efd9
--- /dev/null
+++ b/src/mesh/api/PacketAPI.cpp
@@ -0,0 +1,100 @@
+#ifdef USE_PACKET_API
+
+#include "api/PacketAPI.h"
+#include "MeshService.h"
+#include "PowerFSM.h"
+#include "RadioInterface.h"
+#include "modules/NodeInfoModule.h"
+
+PacketAPI *packetAPI = nullptr;
+
+PacketAPI *PacketAPI::create(PacketServer *_server)
+{
+ if (!packetAPI) {
+ packetAPI = new PacketAPI(_server);
+ }
+ return packetAPI;
+}
+
+PacketAPI::PacketAPI(PacketServer *_server) : concurrency::OSThread("PacketAPI"), isConnected(false), server(_server) {}
+
+int32_t PacketAPI::runOnce()
+{
+ bool success = sendPacket();
+ success |= receivePacket();
+ return success ? 10 : 50;
+}
+
+bool PacketAPI::receivePacket(void)
+{
+ bool data_received = false;
+ while (server->hasData()) {
+ isConnected = true;
+ data_received = true;
+
+ powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
+ lastContactMsec = millis();
+
+ meshtastic_ToRadio *mr;
+ auto p = server->receivePacket()->move();
+ int id = p->getPacketId();
+ LOG_DEBUG("Received packet id=%u", id);
+ mr = (meshtastic_ToRadio *)&static_cast *>(p.get())->getData();
+
+ switch (mr->which_payload_variant) {
+ case meshtastic_ToRadio_packet_tag: {
+ meshtastic_MeshPacket *mp = &mr->packet;
+ printPacket("PACKET FROM QUEUE", mp);
+ service->handleToRadio(*mp);
+ break;
+ }
+ case meshtastic_ToRadio_want_config_id_tag: {
+ uint32_t config_nonce = mr->want_config_id;
+ LOG_INFO("Screen wants config, nonce=%u", config_nonce);
+ handleStartConfig();
+ break;
+ }
+ case meshtastic_ToRadio_heartbeat_tag:
+ if (mr->heartbeat.dummy_field == 1) {
+ if (nodeInfoModule) {
+ LOG_INFO("Broadcasting nodeinfo ping");
+ nodeInfoModule->sendOurNodeInfo(NODENUM_BROADCAST, true, 0, true);
+ }
+ } else {
+ LOG_DEBUG("Got client heartbeat");
+ }
+ break;
+ default:
+ LOG_ERROR("Error: unhandled meshtastic_ToRadio variant: %d", mr->which_payload_variant);
+ break;
+ }
+ }
+ return data_received;
+}
+
+bool PacketAPI::sendPacket(void)
+{
+ // fill dummy buffer; we don't use it, we directly send the fromRadio structure
+ uint32_t len = getFromRadio(txBuf);
+ if (len != 0) {
+ static uint32_t id = 0;
+ fromRadioScratch.id = ++id;
+ // TODO: think about redesign or drop class MeshPacketServer
+ // if (typeid(*server) == typeid(MeshPacketServer))
+ // return dynamic_cast(server)->sendPacket(fromRadioScratch);
+ // else
+ return server->sendPacket(DataPacket(id, fromRadioScratch));
+ } else
+ return false;
+}
+
+/**
+ * return true if we got (once!) contact from our client and the server send queue is not full
+ */
+bool PacketAPI::checkIsConnected()
+{
+ isConnected |= server->hasData();
+ return isConnected && server->available();
+}
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/api/PacketAPI.h b/src/mesh/api/PacketAPI.h
new file mode 100644
index 0000000000..f9ae0812a6
--- /dev/null
+++ b/src/mesh/api/PacketAPI.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "PacketServer.h"
+#include "PhoneAPI.h"
+#include "concurrency/OSThread.h"
+
+/**
+ * A version of the phone API used for inter task communication based on protobuf packets, e.g.
+ * between two tasks running on CPU0 and CPU1, respectively.
+ *
+ */
+class PacketAPI : public PhoneAPI, public concurrency::OSThread
+{
+ public:
+ static PacketAPI *create(PacketServer *_server);
+ virtual ~PacketAPI(){};
+ virtual int32_t runOnce();
+
+ protected:
+ PacketAPI(PacketServer *_server);
+ // Check the current underlying physical queue to see if the client is fetching packets
+ bool checkIsConnected() override;
+
+ void onNowHasData(uint32_t fromRadioNum) override {}
+ void onConnectionChanged(bool connected) override {}
+
+ private:
+ bool receivePacket(void);
+ bool sendPacket(void);
+
+ bool isConnected;
+ PacketServer *server;
+ uint8_t txBuf[MAX_TO_FROM_RADIO_SIZE] = {0}; // dummy buf to obey PhoneAPI
+};
+
+extern PacketAPI *packetAPI;
\ No newline at end of file
diff --git a/src/mesh/http/ContentHelper.h b/src/mesh/http/ContentHelper.h
index a80c39f47f..e5d3a2f571 100644
--- a/src/mesh/http/ContentHelper.h
+++ b/src/mesh/http/ContentHelper.h
@@ -1,5 +1,6 @@
#include
#include
+#include
#define BoolToString(x) ((x) ? "true" : "false")
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index 90722f5472..fe7a0514d2 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -175,6 +175,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
LOG_INFO("Client is setting ham mode");
handleSetHamMode(r->set_ham_mode);
break;
+ case meshtastic_AdminMessage_get_ui_config_request_tag: {
+ LOG_INFO("Client is getting device-ui config");
+ handleGetDeviceUIConfig(mp);
+ handled = true;
+ break;
+ }
/**
* Other
@@ -234,6 +240,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
reboot(DEFAULT_REBOOT_SECONDS);
break;
}
+ case meshtastic_AdminMessage_store_ui_config_tag: {
+ LOG_INFO("Storing device-ui config");
+ handleStoreDeviceUIConfig(r->store_ui_config);
+ handled = true;
+ break;
+ }
case meshtastic_AdminMessage_begin_edit_settings_tag: {
LOG_INFO("Beginning transaction for editing settings");
hasOpenEditTransaction = true;
@@ -594,6 +606,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
requiresReboot = false;
break;
+ case meshtastic_Config_device_ui_tag:
+ // NOOP! This is handled by handleStoreDeviceUIConfig
+ break;
}
if (requiresReboot && !hasOpenEditTransaction) {
disableBluetooth();
@@ -756,6 +771,10 @@ void AdminModule::handleGetConfig(const meshtastic_MeshPacket &req, const uint32
LOG_INFO("Getting config: Sessionkey");
res.get_config_response.which_payload_variant = meshtastic_Config_sessionkey_tag;
break;
+ case meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG:
+ // NOOP! This is handled by handleGetDeviceUIConfig
+ res.get_config_response.which_payload_variant = meshtastic_Config_device_ui_tag;
+ break;
}
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
@@ -968,6 +987,14 @@ void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t ch
}
}
+void AdminModule::handleGetDeviceUIConfig(const meshtastic_MeshPacket &req)
+{
+ meshtastic_AdminMessage r = meshtastic_AdminMessage_init_default;
+ r.which_payload_variant = meshtastic_AdminMessage_get_ui_config_response_tag;
+ r.get_ui_config_response = uiconfig;
+ myReply = allocDataProtobuf(r);
+}
+
void AdminModule::reboot(int32_t seconds)
{
LOG_INFO("Rebooting in %d seconds", seconds);
@@ -988,6 +1015,11 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
}
}
+void AdminModule::handleStoreDeviceUIConfig(const meshtastic_DeviceUIConfig &uicfg)
+{
+ nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uicfg);
+}
+
void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
{
// Set call sign and override lora limitations for licensed use
@@ -1054,7 +1086,8 @@ bool AdminModule::messageIsResponse(const meshtastic_AdminMessage *r)
r->which_payload_variant == meshtastic_AdminMessage_get_ringtone_response_tag ||
r->which_payload_variant == meshtastic_AdminMessage_get_device_connection_status_response_tag ||
r->which_payload_variant == meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag ||
- r->which_payload_variant == meshtastic_NodeRemoteHardwarePinsResponse_node_remote_hardware_pins_tag)
+ r->which_payload_variant == meshtastic_NodeRemoteHardwarePinsResponse_node_remote_hardware_pins_tag ||
+ r->which_payload_variant == meshtastic_AdminMessage_get_ui_config_response_tag)
return true;
else
return false;
@@ -1070,7 +1103,8 @@ bool AdminModule::messageIsRequest(const meshtastic_AdminMessage *r)
r->which_payload_variant == meshtastic_AdminMessage_get_device_metadata_request_tag ||
r->which_payload_variant == meshtastic_AdminMessage_get_ringtone_request_tag ||
r->which_payload_variant == meshtastic_AdminMessage_get_device_connection_status_request_tag ||
- r->which_payload_variant == meshtastic_AdminMessage_get_node_remote_hardware_pins_request_tag)
+ r->which_payload_variant == meshtastic_AdminMessage_get_node_remote_hardware_pins_request_tag ||
+ r->which_payload_variant == meshtastic_AdminMessage_get_ui_config_request_tag)
return true;
else
return false;
diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h
index e54b89af1c..766b2930c7 100644
--- a/src/modules/AdminModule.h
+++ b/src/modules/AdminModule.h
@@ -41,6 +41,7 @@ class AdminModule : public ProtobufModule, public Obser
void handleGetDeviceMetadata(const meshtastic_MeshPacket &req);
void handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req);
void handleGetNodeRemoteHardwarePins(const meshtastic_MeshPacket &req);
+ void handleGetDeviceUIConfig(const meshtastic_MeshPacket &req);
/**
* Setters
*/
@@ -50,6 +51,7 @@ class AdminModule : public ProtobufModule, public Obser
void handleSetModuleConfig(const meshtastic_ModuleConfig &c);
void handleSetChannel();
void handleSetHamMode(const meshtastic_HamParameters &req);
+ void handleStoreDeviceUIConfig(const meshtastic_DeviceUIConfig &uicfg);
void reboot(int32_t seconds);
void setPassKey(meshtastic_AdminMessage *res);
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index 90c8c0f2cc..5a406d966b 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -971,6 +971,7 @@ bool CannedMessageModule::interceptingKeyboardInput()
}
}
+#if !HAS_TFT
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
char buffer[50];
@@ -1129,6 +1130,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
}
}
}
+#endif
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
{
diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h
index e9dc2bda0a..5504af117e 100644
--- a/src/modules/CannedMessageModule.h
+++ b/src/modules/CannedMessageModule.h
@@ -113,8 +113,10 @@ class CannedMessageModule : public SinglePortModule, public ObservableshouldDraw(); }
virtual Observable *getUIFrameObservable() override { return this; }
- virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
virtual bool interceptingKeyboardInput() override;
+#if !HAS_TFT
+ virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
+#endif
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response) override;
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index ad3f0ace45..809a8d87b0 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -74,7 +74,7 @@
#include "modules/StoreForwardModule.h"
#endif
#endif
-#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
+#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
#include "modules/ExternalNotificationModule.h"
#endif
@@ -173,7 +173,7 @@ void setupModules()
aSerialKeyboardImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
#endif // HAS_BUTTON
-#if ARCH_PORTDUINO
+#if ARCH_PORTDUINO && !HAS_TFT
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
#endif
@@ -223,7 +223,7 @@ void setupModules()
storeForwardModule = new StoreForwardModule();
#endif
#endif
-#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
+#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
externalNotificationModule = new ExternalNotificationModule();
#endif
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index 78562e47a7..ca663085c5 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -96,6 +96,7 @@ void portduinoSetup()
std::string gpioChipName = "gpiochip";
settingsStrings[i2cdev] = "";
settingsStrings[keyboardDevice] = "";
+ settingsStrings[pointerDevice] = "";
settingsStrings[webserverrootpath] = "";
settingsStrings[spidev] = "";
settingsStrings[displayspidev] = "";
@@ -333,6 +334,8 @@ bool loadConfig(const char *configPath)
settingsMap[displayPanel] = ili9341;
else if (yamlConfig["Display"]["Panel"].as("") == "ILI9342")
settingsMap[displayPanel] = ili9342;
+ else if (yamlConfig["Display"]["Panel"].as("") == "ILI9486")
+ settingsMap[displayPanel] = ili9486;
else if (yamlConfig["Display"]["Panel"].as("") == "ILI9488")
settingsMap[displayPanel] = ili9488;
else if (yamlConfig["Display"]["Panel"].as("") == "HX8357D")
@@ -393,6 +396,7 @@ bool loadConfig(const char *configPath)
}
if (yamlConfig["Input"]) {
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as("");
+ settingsStrings[pointerDevice] = (yamlConfig["Input"]["PointerDevice"]).as("");
}
if (yamlConfig["Webserver"]) {
diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h
index 95d82c1a21..d1a7f96471 100644
--- a/src/platform/portduino/PortduinoGlue.h
+++ b/src/platform/portduino/PortduinoGlue.h
@@ -48,6 +48,7 @@ enum configNames {
displayOffsetY,
displayInvert,
keyboardDevice,
+ pointerDevice,
logoutputlevel,
traceFilename,
webserver,
@@ -58,7 +59,7 @@ enum configNames {
ascii_logs,
config_directory
};
-enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9488, hx8357d };
+enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d };
enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 };
enum { level_error, level_warn, level_info, level_debug, level_trace };
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 3bc1042bb5..5b029b7181 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -58,7 +58,7 @@ RTC_DATA_ATTR int bootCount = 0;
*/
void setCPUFast(bool on)
{
-#if defined(ARCH_ESP32) && HAS_WIFI
+#if defined(ARCH_ESP32) && HAS_WIFI && !HAS_TFT
if (isWifiAvailable()) {
/*
@@ -376,6 +376,9 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
gpio_wakeup_enable(pin, GPIO_INTR_LOW_LEVEL);
esp_sleep_enable_gpio_wakeup();
#endif
+#ifdef INPUTDRIVER_ENCODER_BTN
+ gpio_wakeup_enable((gpio_num_t)INPUTDRIVER_ENCODER_BTN, GPIO_INTR_LOW_LEVEL);
+#endif
#ifdef T_WATCH_S3
gpio_wakeup_enable((gpio_num_t)SCREEN_TOUCH_INT, GPIO_INTR_LOW_LEVEL);
#endif
diff --git a/variants/picomputer-s3/platformio.ini b/variants/picomputer-s3/platformio.ini
index 202cd05e70..8bffdcaa78 100644
--- a/variants/picomputer-s3/platformio.ini
+++ b/variants/picomputer-s3/platformio.ini
@@ -1,4 +1,4 @@
-[env:picomputer-s3]
+[env:picomputer-s3-oled]
extends = esp32s3_base
board = bpi_picow_esp32_s3
@@ -15,3 +15,47 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
lovyan03/LovyanGFX@^1.1.8
+
+
+[env:picomputer-s3]
+extends = esp32s3_base
+board = bpi_picow_esp32_s3
+board_build.partitions = default_8MB.csv ; just for test
+board_check = true
+upload_protocol = esptool
+build_flags = ${esp32_base.build_flags}
+ -D PICOMPUTER_S3
+ -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
+ -D MESHTASTIC_EXCLUDE_INPUTBROKER=1
+ -D MESHTASTIC_EXCLUDE_BLUETOOTH=1
+ -D INPUTDRIVER_MATRIX_TYPE=1
+ -D USE_PIN_BUZZER=PIN_BUZZER
+ -D USE_SX127x
+ -D MAX_NUM_NODES=200
+ -D HAS_SCREEN=0
+ -D HAS_TFT=1
+ -D RAM_SIZE=1024
+ -D LV_LVGL_H_INCLUDE_SIMPLE
+ -D LV_CONF_INCLUDE_SIMPLE
+ -D LV_COMP_CONF_INCLUDE_SIMPLE
+ -D LV_USE_SYSMON=0
+ -D LV_USE_PROFILER=0
+ -D LV_USE_PERF_MONITOR=0
+ -D LV_USE_MEM_MONITOR=0
+ -D LV_USE_LOG=0
+ -D USE_LOG_DEBUG
+ -D LOG_DEBUG_INC=\"DebugConfiguration.h\"
+ -D LGFX_DRIVER=LGFX_PICOMPUTER_S3
+ -D VIEW_320x240
+; -D USE_DOUBLE_BUFFER
+ -D USE_PACKET_API
+ -I lib/device-ui/generated/ui_320x240
+ -I variants/picomputer-s3
+build_src_filter = ${esp32_base.build_src_filter}
+ +<../lib/device-ui/generated/ui_320x240>
+ +<../lib/device-ui/resources>
+ +<../lib/device-ui/locale>
+ +<../lib/device-ui/source>
+lib_deps =
+ ${esp32_base.lib_deps}
+ lovyan03/LovyanGFX@^1.1.16
diff --git a/variants/portduino/platformio.ini b/variants/portduino/platformio.ini
index 46417e388e..fa4731ec86 100644
--- a/variants/portduino/platformio.ini
+++ b/variants/portduino/platformio.ini
@@ -8,3 +8,87 @@ build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino -I /usr/in
board = cross_platform
lib_deps = ${portduino_base.lib_deps}
build_src_filter = ${portduino_base.build_src_filter}
+
+[env:native-tft-debug]
+extends = portduino_base
+build_type = debug
+build_flags = ${portduino_base.build_flags} -O0 -fsanitize=address -lX11 -linput -lxkbcommon
+ -D ARCH_PORTDUINO
+ -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
+ -I variants/portduino
+ -I /usr/include
+ -D DEBUG_HEAP
+ -D RAM_SIZE=16384
+ -D USE_X11=1 ; enables usage of X11
+ -D HAS_TFT=1
+ -D HAS_SCREEN=0
+; -D CALIBRATE_TOUCH=0
+ -D LV_BUILD_TEST=0
+ -D LV_USE_LOG=1
+ -D LV_USE_SYSMON=1
+ -D LV_USE_PERF_MONITOR=1
+ -D LV_USE_MEM_MONITOR=0
+ -D LV_USE_PROFILER=0
+ -D LV_USE_LIBINPUT=1
+ -D LV_LVGL_H_INCLUDE_SIMPLE
+ -D LV_CONF_INCLUDE_SIMPLE
+ -D LV_COMP_CONF_INCLUDE_SIMPLE
+ -D USE_LOG_DEBUG
+ -D LOG_DEBUG_INC=\"DebugConfiguration.h\"
+ -D USE_PACKET_API
+ -I lib/device-ui/generated/ui_320x240
+; The pkg-config commands below optionally add link flags.
+; the || : is just a "or run the null command" to avoid returning an error code
+ !pkg-config --libs libulfius --silence-errors || :
+ !pkg-config --libs openssl --silence-errors || :
+board = cross_platform
+build_src_filter = ${portduino_base.build_src_filter}
+ -
+ +<../lib/device-ui/generated/ui_320x240>
+ +<../lib/device-ui/generated/ui_320x240/fonts>
+ +<../lib/device-ui/resources>
+ +<../lib/device-ui/portduino>
+ +<../lib/device-ui/locale>
+ +<../lib/device-ui/source>
+
+
+[env:native-tft-release]
+extends = portduino_base
+build_type = release
+build_flags = ${portduino_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunction-sections -fdata-sections -Wl,--gc-sections
+ -D ARCH_PORTDUINO
+ -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
+ -I variants/portduino
+ -I /usr/include
+ -D RAM_SIZE=16384
+ -D USE_X11=1 ; enables usage of X11
+ -D HAS_TFT=1
+ -D HAS_SCREEN=0
+ -D LV_BUILD_TEST=0
+; -D CALIBRATE_TOUCH=0
+ -D LV_USE_LOG=0
+ -D LV_USE_SYSMON=0
+ -D LV_USE_PROFILER=0
+ -D LV_USE_PERF_MONITOR=0
+ -D LV_USE_MEM_MONITOR=0
+ -D LV_USE_LIBINPUT=1
+ -D LV_LVGL_H_INCLUDE_SIMPLE
+ -D LV_CONF_INCLUDE_SIMPLE
+ -D LV_COMP_CONF_INCLUDE_SIMPLE
+ -D USE_LOG_DEBUG
+ -D LOG_DEBUG_INC=\"DebugConfiguration.h\"
+ -D USE_PACKET_API
+ -I lib/device-ui/generated/ui_320x240
+; The pkg-config commands below optionally add link flags.
+; the || : is just a "or run the null command" to avoid returning an error code
+ !pkg-config --libs libulfius --silence-errors || :
+ !pkg-config --libs openssl --silence-errors || :
+board = cross_platform
+build_src_filter = ${portduino_base.build_src_filter}
+ -
+ +<../lib/device-ui/generated/ui_320x240>
+ +<../lib/device-ui/generated/ui_320x240/fonts>
+ +<../lib/device-ui/resources>
+ +<../lib/device-ui/portduino>
+ +<../lib/device-ui/locale>
+ +<../lib/device-ui/source>
\ No newline at end of file
diff --git a/variants/portduino/variant.h b/variants/portduino/variant.h
index b7b39d6e84..ce7dbd865c 100644
--- a/variants/portduino/variant.h
+++ b/variants/portduino/variant.h
@@ -1,4 +1,6 @@
+#ifndef HAS_SCREEN
#define HAS_SCREEN 1
+#endif
#define CANNED_MESSAGE_MODULE_ENABLE 1
#define HAS_GPS 1
#define MAX_RX_TOPHONE settingsMap[maxtophone]
diff --git a/variants/rak2560/RAK9154Sensor.cpp b/variants/rak2560/RAK9154Sensor.cpp
index 9f660947e8..5fb09c1307 100644
--- a/variants/rak2560/RAK9154Sensor.cpp
+++ b/variants/rak2560/RAK9154Sensor.cpp
@@ -37,11 +37,11 @@ static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT
break;
case SNHUBAPI_EVT_ADD_SID:
- // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]);
+ // LOG_INFO("+ADD:SID:[%02x]", msg[0]);
break;
case SNHUBAPI_EVT_ADD_PID:
- // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]);
+ // LOG_INFO("+ADD:PID:[%02x]", msg[0]);
#ifdef BOOT_DATA_REQ
provision = msg[0];
#endif
@@ -55,12 +55,12 @@ static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT
case SNHUBAPI_EVT_SDATA_REQ:
- // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]);
+ // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]",pid,msg[0]);
// for( uint16_t i=1; i
+ +<../lib/device-ui/resources>
+ +<../lib/device-ui/locale>
+ +<../lib/device-ui/source>
+lib_deps = ${esp32s3_base.lib_deps}
+ https://github.com/mverch67/LovyanGFX#develop
+; file:///home/manuel/Documents/PlatformIO/Projects/LovyanGFX
+ bitbank2/bb_captouch@1.2.2 ; alternative touch library supporting FT6x36
+ earlephilhower/ESP8266Audio@^1.9.7
+ earlephilhower/ESP8266SAM@^1.0.1
diff --git a/variants/seeed-sensecap-indicator/variant.h b/variants/seeed-sensecap-indicator/variant.h
index d7ed329eb9..fe07c34b42 100644
--- a/variants/seeed-sensecap-indicator/variant.h
+++ b/variants/seeed-sensecap-indicator/variant.h
@@ -19,8 +19,7 @@
#define ST7701_BL 45
#define ST7701_SPI_HOST SPI2_HOST
#define ST7701_BACKLIGHT_EN 45
-#define SPI_FREQUENCY 20000000
-#define SPI_READ_FREQUENCY 16000000
+#define SPI_FREQUENCY 12000000
#define TFT_HEIGHT 480
#define TFT_WIDTH 480
#define TFT_OFFSET_X 0
diff --git a/variants/t-deck/platformio.ini b/variants/t-deck/platformio.ini
index a63ff57a75..a459cd0164 100644
--- a/variants/t-deck/platformio.ini
+++ b/variants/t-deck/platformio.ini
@@ -2,18 +2,60 @@
[env:t-deck]
extends = esp32s3_base
board = t-deck
+board_level = extra
+board_build.partitions = default_16MB.csv ; just for test
board_check = true
upload_protocol = esptool
-#upload_port = COM29
-
-build_flags = ${esp32_base.build_flags}
- -DT_DECK
- -DBOARD_HAS_PSRAM
- -DMAX_THREADS=40
- -DGPS_POWER_TOGGLE
- -Ivariants/t-deck
-
-lib_deps = ${esp32s3_base.lib_deps}
- lovyan03/LovyanGFX@^1.1.9
+build_flags = ${esp32_base.build_flags}
+ -D T_DECK
+ -D CONFIG_DISABLE_HAL_LOCKS=1 ; "feels" to be a bit more stable without locks
+ -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
+ -D MESHTASTIC_EXCLUDE_INPUTBROKER=1
+ -D MESHTASTIC_EXCLUDE_BLUETOOTH=1
+ -D MESHTASTIC_EXCLUDE_WEBSERVER=1
+ -D INPUTDRIVER_I2C_KBD_TYPE=0x55
+ -D INPUTDRIVER_ENCODER_TYPE=3
+ -D INPUTDRIVER_ENCODER_LEFT=1
+ -D INPUTDRIVER_ENCODER_RIGHT=2
+ -D INPUTDRIVER_ENCODER_UP=3
+ -D INPUTDRIVER_ENCODER_DOWN=15
+ -D INPUTDRIVER_ENCODER_BTN=0
+ -D MAX_NUM_NODES=250
+ -D MAX_THREADS=40
+ -D HAS_SCREEN=0
+ -D HAS_TFT=1
+ -D USE_I2S_BUZZER
+ -D RAM_SIZE=1024
+ -D GPS_POWER_TOGGLE
+ -D LV_LVGL_H_INCLUDE_SIMPLE
+ -D LV_CONF_INCLUDE_SIMPLE
+ -D LV_COMP_CONF_INCLUDE_SIMPLE
+ -D LV_USE_SYSMON=0
+ -D LV_USE_PROFILER=0
+ -D LV_USE_PERF_MONITOR=0
+ -D LV_USE_MEM_MONITOR=0
+ -D LV_USE_LOG=0
+ -D USE_LOG_DEBUG
+ -D LOG_DEBUG_INC=\"DebugConfiguration.h\"
+ -D RADIOLIB_SPI_PARANOID=0
+ -D CUSTOM_TOUCH_DRIVER
+ -D CALIBRATE_TOUCH=0
+ -D LGFX_DRIVER=LGFX_TDECK
+; -D LVGL_DRIVER=LVGL_TDECK
+; -D LV_USE_ST7789=1
+ -D VIEW_320x240
+; -D USE_DOUBLE_BUFFER
+ -D USE_PACKET_API
+ -I lib/device-ui/generated/ui_320x240
+ -I variants/t-deck
+build_src_filter = ${esp32_base.build_src_filter}
+ +<../lib/device-ui/generated/ui_320x240>
+ +<../lib/device-ui/resources>
+ +<../lib/device-ui/locale>
+ +<../lib/device-ui/source>
+lib_deps =
+ ${esp32_base.lib_deps}
+ lovyan03/LovyanGFX@^1.1.16
+ bitbank2/bb_captouch@1.2.2 ; alternative touch library supporting GT911
earlephilhower/ESP8266Audio@^1.9.7
earlephilhower/ESP8266SAM@^1.0.1
\ No newline at end of file
diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h
index 9860d608f8..53bb706244 100644
--- a/variants/t-deck/variant.h
+++ b/variants/t-deck/variant.h
@@ -1,5 +1,5 @@
// ST7789 TFT LCD
-#define ST7789_CS 12
+// #define ST7789_CS 12
#define ST7789_RS 11 // DC
#define ST7789_SDA 41 // MOSI
#define ST7789_SCK 40
@@ -27,8 +27,10 @@
#define SLEEP_TIME 120
+#ifndef HAS_TFT
#define BUTTON_PIN 0
// #define BUTTON_NEED_PULLUP
+#endif
#define GPS_RX_PIN 44
#define GPS_TX_PIN 43
@@ -60,7 +62,7 @@
#define TB_DOWN 15
#define TB_LEFT 1
#define TB_RIGHT 2
-#define TB_PRESS BUTTON_PIN
+#define TB_PRESS 0 // BUTTON_PIN
// microphone
#define ES7210_SCK 47
diff --git a/variants/tlora_t3s3_v1/platformio.ini b/variants/tlora_t3s3_v1/platformio.ini
index 0a57972803..c062dbd7b0 100644
--- a/variants/tlora_t3s3_v1/platformio.ini
+++ b/variants/tlora_t3s3_v1/platformio.ini
@@ -6,4 +6,73 @@ upload_protocol = esptool
build_flags =
${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1
- -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
\ No newline at end of file
+ -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
+
+
+[env:tlora-t3s3-tft]
+extends = esp32s3_base
+board = tlora-t3s3-v1
+;board_check = true
+upload_protocol = esp-builtin
+
+build_flags = ${esp32_base.build_flags}
+ -D TLORA_T3S3_V1
+ -D MESHTASTIC_EXCLUDE_SCREEN=1
+ -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
+ -D MESHTASTIC_EXCLUDE_INPUTBROKER=1
+ -D MESHTASTIC_EXCLUDE_PAXCOUNTER=1
+ -D MESHTASTIC_EXCLUDE_WEBSERVER=1
+ -D MESHTASTIC_EXCLUDE_GPS=1
+ -D MESHTASTIC_EXCLUDE_AUDIO=1
+ -D MESHTASTIC_EXCLUDE_POWER_TELEMETRY=1
+ -D MESHTASTIC_EXCLUDE_ATAK=1
+ -D MESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
+ -D MAX_NUM_NODES=250
+ -D HAS_SCREEN=0
+ -D HAS_TFT=1
+ -D RAM_SIZE=1024
+ -D LV_LVGL_H_INCLUDE_SIMPLE
+ -D LV_CONF_INCLUDE_SIMPLE
+ -D LV_COMP_CONF_INCLUDE_SIMPLE
+ -D LV_USE_SYSMON=0
+ -D LV_USE_PROFILER=0
+ -D LV_USE_PERF_MONITOR=0
+ -D LV_USE_MEM_MONITOR=0
+ -D LV_USE_LOG=0
+ -D USE_LOG_DEBUG
+ -D LOG_DEBUG_INC=\"DebugConfiguration.h\"
+; -D CALIBRATE_TOUCH=0
+ -D LGFX_DRIVER_TEMPLATE
+ -D LGFX_DRIVER=LGFX_GENERIC
+ -D LGFX_PANEL=ST7789
+ -D LGFX_OFFSET_ROTATION=1
+ -D LGFX_TOUCH=XPT2046
+ -D LGFX_PIN_SCK=12
+ -D LGFX_PIN_MOSI=15
+ -D LGFX_PIN_MISO=16
+ -D LGFX_PIN_DC=47
+ -D LGFX_PIN_CS=48
+ -D LGFX_PIN_RST=34
+ -D LGFX_PIN_BL=35
+ -D LGFX_TOUCH_INT=38
+ -D LGFX_TOUCH_CS=39
+ -D LGFX_TOUCH_CLK=12
+ -D LGFX_TOUCH_DO=15
+ -D LGFX_TOUCH_DIN=16
+ -D LGFX_TOUCH_X_MIN=300
+ -D LGFX_TOUCH_X_MAX=3900
+ -D LGFX_TOUCH_Y_MIN=400
+ -D LGFX_TOUCH_Y_MAX=3900
+ -D VIEW_320x240
+; -D USE_DOUBLE_BUFFER
+ -D USE_PACKET_API
+ -I variants/tlora_t3s3_v1
+ -I lib/device-ui/generated/ui_320x240
+build_src_filter = ${esp32_base.build_src_filter}
+ +<../lib/device-ui/generated/ui_320x240>
+ +<../lib/device-ui/resources>
+ +<../lib/device-ui/locale>
+ +<../lib/device-ui/source>
+lib_deps =
+ ${esp32_base.lib_deps}
+ lovyan03/LovyanGFX@^1.1.16
diff --git a/variants/unphone/pins_arduino.h b/variants/unphone/pins_arduino.h
index c4e9add1c3..74067359fc 100644
--- a/variants/unphone/pins_arduino.h
+++ b/variants/unphone/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x16D0
#define USB_PID 0x1178
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
#define LED_BUILTIN 13
#define BUILTIN_LED LED_BUILTIN // backward compatibility
diff --git a/variants/unphone/platformio.ini b/variants/unphone/platformio.ini
index 489c70f998..b41848e134 100644
--- a/variants/unphone/platformio.ini
+++ b/variants/unphone/platformio.ini
@@ -26,7 +26,7 @@ build_flags = ${esp32_base.build_flags}
build_src_filter = ${esp32_base.build_src_filter} +<../variants/unphone>
lib_deps = ${esp32s3_base.lib_deps}
- lovyan03/LovyanGFX@ 1.1.12
+ lovyan03/LovyanGFX@ 1.1.16
https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic@9.0.0
adafruit/Adafruit NeoPixel @ ^1.12.0
@@ -46,19 +46,29 @@ build_flags = ${esp32_base.build_flags}
-D UNPHONE_UI0=0
-D UNPHONE_LORA=0
-D UNPHONE_FACTORY_MODE=0
+ -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
+ -D MESHTASTIC_EXCLUDE_INPUTBROKER=1
+ -D MESHTASTIC_EXCLUDE_BLUETOOTH=1
+ -D MESHTASTIC_EXCLUDE_WEBSERVER=1
+ -D USE_SX127x
+ -D MAX_NUM_NODES=200
-D MAX_THREADS=40
-D HAS_SCREEN=0
-D HAS_TFT=1
- -D RAM_SIZE=512
+ -D DISPLAY_SET_RESOLUTION
+ -D RAM_SIZE=1024
-D LV_LVGL_H_INCLUDE_SIMPLE
-D LV_CONF_INCLUDE_SIMPLE
-D LV_COMP_CONF_INCLUDE_SIMPLE
-D LV_BUILD_TEST=0
+ -D LV_USE_SYSMON=0
+ -D LV_USE_PROFILER=0
-D LV_USE_PERF_MONITOR=0
-D LV_USE_MEM_MONITOR=0
+ -D LV_USE_LOG=0
-D USE_LOG_DEBUG
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
-; -D CALIBRATE_TOUCH=0
+ -D CALIBRATE_TOUCH=0
-D LGFX_DRIVER=LGFX_UNPHONE_V9
-D VIEW_320x240
; -D USE_DOUBLE_BUFFER
@@ -69,9 +79,10 @@ build_flags = ${esp32_base.build_flags}
build_src_filter = ${esp32_base.build_src_filter} +<../variants/unphone>
+<../lib/device-ui/generated/ui_320x240>
+<../lib/device-ui/resources>
+ +<../lib/device-ui/locale>
+<../lib/device-ui/source>
lib_deps = ${esp32s3_base.lib_deps}
- lovyan03/LovyanGFX@^1.1.12
+ lovyan03/LovyanGFX@^1.1.16
https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic@9.0.0
adafruit/Adafruit NeoPixel@1.12.0
\ No newline at end of file