mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-17 23:37:44 +00:00
Compare commits
42 Commits
mini-epape
...
InkHUD-Imp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b6ed2da20 | ||
|
|
91dd39a651 | ||
|
|
d493f5f171 | ||
|
|
e73e817bf2 | ||
|
|
db0ca0324e | ||
|
|
750f695bbd | ||
|
|
2cbb8040f3 | ||
|
|
ef128a7883 | ||
|
|
d55bf66f25 | ||
|
|
1885a2beac | ||
|
|
d5ef68314b | ||
|
|
3baba4b1a1 | ||
|
|
791fb86c7c | ||
|
|
c1c5d36e86 | ||
|
|
050371adc5 | ||
|
|
f409645ad3 | ||
|
|
25d7db65ea | ||
|
|
e0ceaaff38 | ||
|
|
6431c76aac | ||
|
|
ac0b3613ec | ||
|
|
9ad7d39051 | ||
|
|
b3e6731c85 | ||
|
|
ef36a5a24d | ||
|
|
66d9c430d8 | ||
|
|
ac05337e42 | ||
|
|
1d4e295471 | ||
|
|
c761444bee | ||
|
|
929aa5c968 | ||
|
|
cc6265e9b1 | ||
|
|
958e1f73ef | ||
|
|
96e82f1ec1 | ||
|
|
83ec37113d | ||
|
|
5acf72243d | ||
|
|
bd18a171d4 | ||
|
|
6e05c554b8 | ||
|
|
5f9a6a38e6 | ||
|
|
a332ca978b | ||
|
|
7b4315421b | ||
|
|
60389e84e6 | ||
|
|
cd0843c7db | ||
|
|
d9dab0cd6c | ||
|
|
87114f4052 |
@@ -20,7 +20,7 @@ ENV PIP_ROOT_USER_ACTION=ignore
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
cmake git zip libgpiod-dev libbluetooth-dev libi2c-dev \
|
||||
libunistring-dev libmicrohttpd-dev libgnutls28-dev libgcrypt20-dev \
|
||||
libusb-1.0-0-dev libssl-dev pkg-config && \
|
||||
libusb-1.0-0-dev libssl-dev pkg-config libsqlite3-dev && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/* && \
|
||||
pip install --no-cache-dir -U \
|
||||
platformio==6.1.16 \
|
||||
|
||||
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
curl wget g++ zip git ca-certificates pkg-config \
|
||||
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
|
||||
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev \
|
||||
libx11-dev libinput-dev libxkbcommon-x11-dev \
|
||||
libx11-dev libinput-dev libxkbcommon-x11-dev libsqlite3-dev \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir -U platformio \
|
||||
&& mkdir /tmp/firmware
|
||||
|
||||
@@ -11,7 +11,7 @@ RUN apk --no-cache add \
|
||||
bash g++ libstdc++-dev linux-headers zip git ca-certificates libbsd-dev \
|
||||
libgpiod-dev yaml-cpp-dev bluez-dev \
|
||||
libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \
|
||||
libx11-dev libinput-dev libxkbcommon-dev \
|
||||
libx11-dev libinput-dev libxkbcommon-dev sqlite-dev \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& pip install --no-cache-dir -U platformio \
|
||||
&& mkdir /tmp/firmware
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_ESP32S3_DEV",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": ["wifi"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "LilyGo Mini-Epapaer-S3 (4 MB Flash, 2MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.lilygo.cc",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
3
debian/control
vendored
3
debian/control
vendored
@@ -25,7 +25,8 @@ Build-Depends: debhelper-compat (= 13),
|
||||
liborcania-dev,
|
||||
libx11-dev,
|
||||
libinput-dev,
|
||||
libxkbcommon-x11-dev
|
||||
libxkbcommon-x11-dev,
|
||||
libsqlite3-dev
|
||||
Standards-Version: 4.6.2
|
||||
Homepage: https://github.com/meshtastic/firmware
|
||||
Rules-Requires-Root: no
|
||||
|
||||
@@ -39,6 +39,7 @@ BuildRequires: pkgconfig(bluez)
|
||||
BuildRequires: pkgconfig(libusb-1.0)
|
||||
BuildRequires: libi2c-devel
|
||||
BuildRequires: pkgconfig(libuv)
|
||||
BuildRequires: pkgconfig(sqlite3)
|
||||
# Web components:
|
||||
BuildRequires: pkgconfig(openssl)
|
||||
BuildRequires: pkgconfig(liborcania)
|
||||
|
||||
@@ -259,18 +259,6 @@ bool EInkDisplay::connect()
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||
}
|
||||
#elif defined(MINI_EPAPER_S3)
|
||||
spi1 = new SPIClass(HSPI);
|
||||
spi1->begin(PIN_SPI1_SCK, PIN_SPI1_MISO, PIN_SPI1_MOSI, PIN_EINK_CS);
|
||||
|
||||
// Create GxEPD2 objects
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
|
||||
// Init GxEPD2
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(0);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
||||
|
||||
// Detect display model, before starting SPI
|
||||
|
||||
@@ -93,8 +93,7 @@ class EInkDisplay : public OLEDDisplay
|
||||
SPIClass *hspi = NULL;
|
||||
#endif
|
||||
|
||||
#if defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK) || defined(HELTEC_MESH_SOLAR_EINK) || \
|
||||
defined(MINI_EPAPER_S3)
|
||||
#if defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK) || defined(HELTEC_MESH_SOLAR_EINK)
|
||||
SPIClass *spi1 = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -155,6 +155,18 @@ void InkHUD::LogoApplet::onShutdown()
|
||||
// This is then drawn by InkHUD::Events::onShutdown, with a blocking FULL update, after InkHUD's flash write is complete
|
||||
}
|
||||
|
||||
void InkHUD::LogoApplet::onApplyingChanges()
|
||||
{
|
||||
bringToForeground();
|
||||
|
||||
textLeft = "";
|
||||
textRight = "";
|
||||
textTitle = "Applying changes";
|
||||
fontTitle = fontSmall;
|
||||
|
||||
inkhud->forceUpdate(Drivers::EInk::FAST, false);
|
||||
}
|
||||
|
||||
void InkHUD::LogoApplet::onReboot()
|
||||
{
|
||||
bringToForeground();
|
||||
|
||||
@@ -26,6 +26,7 @@ class LogoApplet : public SystemApplet, public concurrency::OSThread
|
||||
void onBackground() override;
|
||||
void onShutdown() override;
|
||||
void onReboot() override;
|
||||
void onApplyingChanges();
|
||||
|
||||
protected:
|
||||
int32_t runOnce() override;
|
||||
|
||||
@@ -22,6 +22,7 @@ enum MenuAction {
|
||||
STORE_CANNEDMESSAGE_SELECTION,
|
||||
SEND_CANNEDMESSAGE,
|
||||
SHUTDOWN,
|
||||
BACK,
|
||||
NEXT_TILE,
|
||||
TOGGLE_BACKLIGHT,
|
||||
TOGGLE_GPS,
|
||||
@@ -36,6 +37,84 @@ enum MenuAction {
|
||||
TOGGLE_NOTIFICATIONS,
|
||||
TOGGLE_INVERT_COLOR,
|
||||
TOGGLE_12H_CLOCK,
|
||||
// Regions
|
||||
SET_REGION_US,
|
||||
SET_REGION_EU_868,
|
||||
SET_REGION_EU_433,
|
||||
SET_REGION_CN,
|
||||
SET_REGION_JP,
|
||||
SET_REGION_ANZ,
|
||||
SET_REGION_KR,
|
||||
SET_REGION_TW,
|
||||
SET_REGION_RU,
|
||||
SET_REGION_IN,
|
||||
SET_REGION_NZ_865,
|
||||
SET_REGION_TH,
|
||||
SET_REGION_LORA_24,
|
||||
SET_REGION_UA_433,
|
||||
SET_REGION_UA_868,
|
||||
SET_REGION_MY_433,
|
||||
SET_REGION_MY_919,
|
||||
SET_REGION_SG_923,
|
||||
SET_REGION_PH_433,
|
||||
SET_REGION_PH_868,
|
||||
SET_REGION_PH_915,
|
||||
SET_REGION_ANZ_433,
|
||||
SET_REGION_KZ_433,
|
||||
SET_REGION_KZ_863,
|
||||
SET_REGION_NP_865,
|
||||
SET_REGION_BR_902,
|
||||
// Device Roles
|
||||
SET_ROLE_CLIENT,
|
||||
SET_ROLE_CLIENT_MUTE,
|
||||
SET_ROLE_ROUTER,
|
||||
SET_ROLE_REPEATER,
|
||||
// Presets
|
||||
SET_PRESET_LONG_SLOW,
|
||||
SET_PRESET_LONG_MODERATE,
|
||||
SET_PRESET_LONG_FAST,
|
||||
SET_PRESET_MEDIUM_SLOW,
|
||||
SET_PRESET_MEDIUM_FAST,
|
||||
SET_PRESET_SHORT_SLOW,
|
||||
SET_PRESET_SHORT_FAST,
|
||||
SET_PRESET_SHORT_TURBO,
|
||||
// Timezones
|
||||
SET_TZ_US_HAWAII,
|
||||
SET_TZ_US_ALASKA,
|
||||
SET_TZ_US_PACIFIC,
|
||||
SET_TZ_US_ARIZONA,
|
||||
SET_TZ_US_MOUNTAIN,
|
||||
SET_TZ_US_CENTRAL,
|
||||
SET_TZ_US_EASTERN,
|
||||
SET_TZ_BR_BRAZILIA,
|
||||
SET_TZ_UTC,
|
||||
SET_TZ_EU_WESTERN,
|
||||
SET_TZ_EU_CENTRAL,
|
||||
SET_TZ_EU_EASTERN,
|
||||
SET_TZ_ASIA_KOLKATA,
|
||||
SET_TZ_ASIA_HONG_KONG,
|
||||
SET_TZ_AU_AWST,
|
||||
SET_TZ_AU_ACST,
|
||||
SET_TZ_AU_AEST,
|
||||
SET_TZ_PACIFIC_NZ,
|
||||
// Power
|
||||
TOGGLE_POWER_SAVE,
|
||||
CALIBRATE_ADC,
|
||||
// Bluetooth
|
||||
TOGGLE_BLUETOOTH,
|
||||
TOGGLE_BLUETOOTH_PAIR_MODE,
|
||||
// Channel
|
||||
TOGGLE_CHANNEL_UPLINK,
|
||||
TOGGLE_CHANNEL_DOWNLINK,
|
||||
TOGGLE_CHANNEL_POSITION,
|
||||
SET_CHANNEL_PRECISION,
|
||||
// Display
|
||||
TOGGLE_DISPLAY_UNITS,
|
||||
// Network
|
||||
TOGGLE_WIFI,
|
||||
// Administration
|
||||
RESET_NODEDB_ALL,
|
||||
RESET_NODEDB_KEEP_FAVORITES,
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@ class MenuApplet : public SystemApplet, public concurrency::OSThread
|
||||
void onRender() override;
|
||||
|
||||
void show(Tile *t); // Open the menu, onto a user tile
|
||||
void setStartPage(MenuPage page);
|
||||
|
||||
protected:
|
||||
Drivers::LatchingBacklight *backlight = nullptr; // Convenient access to the backlight singleton
|
||||
@@ -56,6 +57,7 @@ class MenuApplet : public SystemApplet, public concurrency::OSThread
|
||||
void sendText(NodeNum dest, ChannelIndex channel, const char *message); // Send a text message to mesh
|
||||
void freeCannedMessageResources(); // Clear MenuApplet's canned message processing data
|
||||
|
||||
MenuPage startPageOverride = MenuPage::ROOT;
|
||||
MenuPage currentPage = MenuPage::ROOT;
|
||||
MenuPage previousPage = MenuPage::EXIT;
|
||||
uint8_t cursor = 0; // Which menu item is currently highlighted
|
||||
@@ -63,7 +65,15 @@ class MenuApplet : public SystemApplet, public concurrency::OSThread
|
||||
|
||||
uint16_t systemInfoPanelHeight = 0; // Need to know before we render
|
||||
|
||||
std::vector<MenuItem> items; // MenuItems for the current page. Filled by ShowPage
|
||||
std::vector<MenuItem> items; // MenuItems for the current page. Filled by ShowPage
|
||||
std::vector<std::string> nodeConfigLabels; // Persistent labels for Node Config pages
|
||||
uint8_t selectedChannelIndex = 0; // Currently selected LoRa channel (Node Config → Radio → Channel)
|
||||
bool channelPositionEnabled = false;
|
||||
bool gpsEnabled = false;
|
||||
|
||||
// Recents menu checkbox state (derived from settings.recentlyActiveSeconds)
|
||||
static constexpr uint8_t RECENTS_COUNT = 6;
|
||||
bool recentsSelected[RECENTS_COUNT] = {};
|
||||
|
||||
// Data for selecting and sending canned messages via the menu
|
||||
// Placed into a sub-class for organization only
|
||||
|
||||
@@ -30,6 +30,7 @@ class MenuItem
|
||||
MenuAction action = NO_ACTION;
|
||||
MenuPage nextPage = EXIT;
|
||||
bool *checkState = nullptr;
|
||||
bool isHeader = false; // Non-selectable section label
|
||||
|
||||
// Various constructors, depending on the intended function of the item
|
||||
|
||||
@@ -40,6 +41,12 @@ class MenuItem
|
||||
: label(label), action(action), nextPage(nextPage), checkState(checkState)
|
||||
{
|
||||
}
|
||||
static MenuItem Header(const char *label)
|
||||
{
|
||||
MenuItem item(label, NO_ACTION, EXIT);
|
||||
item.isHeader = true;
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
@@ -20,10 +20,27 @@ enum MenuPage : uint8_t {
|
||||
SEND,
|
||||
CANNEDMESSAGE_RECIPIENT, // Select destination for a canned message
|
||||
OPTIONS,
|
||||
NODE_CONFIG,
|
||||
NODE_CONFIG_LORA,
|
||||
NODE_CONFIG_CHANNELS, // List of channels
|
||||
NODE_CONFIG_CHANNEL_DETAIL, // Per-channel options
|
||||
NODE_CONFIG_CHANNEL_PRECISION,
|
||||
NODE_CONFIG_PRESET,
|
||||
NODE_CONFIG_DEVICE,
|
||||
NODE_CONFIG_DEVICE_ROLE,
|
||||
NODE_CONFIG_POWER,
|
||||
NODE_CONFIG_POWER_ADC_CAL,
|
||||
NODE_CONFIG_NETWORK,
|
||||
NODE_CONFIG_DISPLAY,
|
||||
NODE_CONFIG_BLUETOOTH,
|
||||
NODE_CONFIG_POSITION,
|
||||
NODE_CONFIG_ADMIN_RESET,
|
||||
TIMEZONE,
|
||||
APPLETS,
|
||||
AUTOSHOW,
|
||||
RECENTS, // Select length of "recentlyActiveSeconds"
|
||||
EXIT, // Dismiss the menu applet
|
||||
REGION,
|
||||
EXIT, // Dismiss the menu applet
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
@@ -10,34 +10,37 @@ using namespace NicheGraphics;
|
||||
|
||||
InkHUD::TipsApplet::TipsApplet()
|
||||
{
|
||||
// Decide which tips (if any) should be shown to user after the boot screen
|
||||
bool needsRegion = (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET);
|
||||
|
||||
bool showTutorialTips = (settings->tips.firstBoot || needsRegion);
|
||||
|
||||
// Welcome screen
|
||||
if (settings->tips.firstBoot)
|
||||
if (showTutorialTips)
|
||||
tipQueue.push_back(Tip::WELCOME);
|
||||
|
||||
// Antenna, region, timezone
|
||||
// Shown at boot if region not yet set
|
||||
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET)
|
||||
// Finish setup
|
||||
if (needsRegion)
|
||||
tipQueue.push_back(Tip::FINISH_SETUP);
|
||||
|
||||
// Using the UI
|
||||
if (showTutorialTips) {
|
||||
tipQueue.push_back(Tip::CUSTOMIZATION);
|
||||
tipQueue.push_back(Tip::BUTTONS);
|
||||
}
|
||||
|
||||
// Shutdown info
|
||||
// Shown until user performs one valid shutdown
|
||||
if (!settings->tips.safeShutdownSeen)
|
||||
tipQueue.push_back(Tip::SAFE_SHUTDOWN);
|
||||
|
||||
// Using the UI
|
||||
if (settings->tips.firstBoot) {
|
||||
tipQueue.push_back(Tip::CUSTOMIZATION);
|
||||
tipQueue.push_back(Tip::BUTTONS);
|
||||
}
|
||||
|
||||
// Catch an incorrect attempt at rotating display
|
||||
if (config.display.flip_screen)
|
||||
tipQueue.push_back(Tip::ROTATION);
|
||||
|
||||
// Applet is foreground immediately at boot, but is obscured by LogoApplet, which is also foreground
|
||||
// LogoApplet can be considered to have a higher Z-index, because it is placed before TipsApplet in the systemApplets vector
|
||||
// Region picker
|
||||
if (needsRegion)
|
||||
tipQueue.push_back(Tip::PICK_REGION);
|
||||
|
||||
if (!tipQueue.empty())
|
||||
bringToForeground();
|
||||
}
|
||||
@@ -51,81 +54,109 @@ void InkHUD::TipsApplet::onRender()
|
||||
|
||||
case Tip::FINISH_SETUP: {
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Finish Setup");
|
||||
const char *title = "Tip: Finish Setup";
|
||||
uint16_t h = getWrappedTextHeight(0, width(), title);
|
||||
printWrapped(0, 0, width(), title);
|
||||
|
||||
setFont(fontSmall);
|
||||
int16_t cursorY = fontMedium.lineHeight() * 1.5;
|
||||
printAt(0, cursorY, "- connect antenna");
|
||||
int16_t cursorY = h + fontSmall.lineHeight();
|
||||
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
printAt(0, cursorY, "- connect a client app");
|
||||
auto drawBullet = [&](const char *text) {
|
||||
uint16_t bh = getWrappedTextHeight(0, width(), text);
|
||||
printWrapped(0, cursorY, width(), text);
|
||||
cursorY += bh + (fontSmall.lineHeight() / 3);
|
||||
};
|
||||
|
||||
// Only if region not set
|
||||
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
printAt(0, cursorY, "- set region");
|
||||
}
|
||||
drawBullet("- connect antenna");
|
||||
drawBullet("- connect a client app");
|
||||
|
||||
// Only if tz not set
|
||||
if (!(*config.device.tzdef && config.device.tzdef[0] != 0)) {
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
printAt(0, cursorY, "- set timezone");
|
||||
}
|
||||
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET)
|
||||
drawBullet("- set region");
|
||||
|
||||
cursorY += fontSmall.lineHeight() * 1.5;
|
||||
printAt(0, cursorY, "More info at meshtastic.org");
|
||||
if (!(*config.device.tzdef && config.device.tzdef[0] != 0))
|
||||
drawBullet("- set timezone");
|
||||
|
||||
cursorY += fontSmall.lineHeight() / 2;
|
||||
drawBullet("More info at meshtastic.org");
|
||||
|
||||
setFont(fontSmall);
|
||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||
} break;
|
||||
|
||||
case Tip::PICK_REGION: {
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Set Region");
|
||||
|
||||
setFont(fontSmall);
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(), "Please select your LoRa region to complete setup.");
|
||||
|
||||
printAt(0, Y(1.0), "Press button to choose", LEFT, BOTTOM);
|
||||
} break;
|
||||
|
||||
case Tip::SAFE_SHUTDOWN: {
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Shutdown");
|
||||
|
||||
const char *title = "Tip: Shutdown";
|
||||
uint16_t h = getWrappedTextHeight(0, width(), title);
|
||||
printWrapped(0, 0, width(), title);
|
||||
|
||||
setFont(fontSmall);
|
||||
std::string shutdown;
|
||||
shutdown += "Before removing power, please shut down from InkHUD menu, or a client app. \n";
|
||||
shutdown += "\n";
|
||||
shutdown += "This ensures data is saved.";
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(), shutdown);
|
||||
int16_t cursorY = h + fontSmall.lineHeight();
|
||||
|
||||
const char *body = "Before removing power, please shut down from InkHUD menu, or a client app.\n\n"
|
||||
"This ensures data is saved.";
|
||||
|
||||
uint16_t bodyH = getWrappedTextHeight(0, width(), body);
|
||||
printWrapped(0, cursorY, width(), body);
|
||||
cursorY += bodyH + (fontSmall.lineHeight() / 2);
|
||||
|
||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||
|
||||
} break;
|
||||
|
||||
case Tip::CUSTOMIZATION: {
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Customization");
|
||||
|
||||
const char *title = "Tip: Customization";
|
||||
uint16_t h = getWrappedTextHeight(0, width(), title);
|
||||
printWrapped(0, 0, width(), title);
|
||||
|
||||
setFont(fontSmall);
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
||||
"Configure & control display with the InkHUD menu. Optional features, layout, rotation, and more.");
|
||||
int16_t cursorY = h + fontSmall.lineHeight();
|
||||
|
||||
const char *body = "Configure & control display with the InkHUD menu. "
|
||||
"Optional features, layout, rotation, and more.";
|
||||
|
||||
uint16_t bodyH = getWrappedTextHeight(0, width(), body);
|
||||
printWrapped(0, cursorY, width(), body);
|
||||
cursorY += bodyH + (fontSmall.lineHeight() / 2);
|
||||
|
||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||
} break;
|
||||
|
||||
case Tip::BUTTONS: {
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Buttons");
|
||||
|
||||
const char *title = "Tip: Buttons";
|
||||
uint16_t h = getWrappedTextHeight(0, width(), title);
|
||||
printWrapped(0, 0, width(), title);
|
||||
|
||||
setFont(fontSmall);
|
||||
int16_t cursorY = fontMedium.lineHeight() * 1.5;
|
||||
int16_t cursorY = h + fontSmall.lineHeight();
|
||||
|
||||
auto drawBullet = [&](const char *text) {
|
||||
uint16_t bh = getWrappedTextHeight(0, width(), text);
|
||||
printWrapped(0, cursorY, width(), text);
|
||||
cursorY += bh + (fontSmall.lineHeight() / 3);
|
||||
};
|
||||
|
||||
if (!settings->joystick.enabled) {
|
||||
printAt(0, cursorY, "User Button");
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
printAt(0, cursorY, "- short press: next");
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
printAt(0, cursorY, "- long press: select / open menu");
|
||||
drawBullet("User Button");
|
||||
drawBullet("- short press: next");
|
||||
drawBullet("- long press: select or open menu");
|
||||
} else {
|
||||
printAt(0, cursorY, "Joystick");
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
printAt(0, cursorY, "- open menu / select");
|
||||
cursorY += fontSmall.lineHeight() * 1.5;
|
||||
printAt(0, cursorY, "Exit Button");
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
printAt(0, cursorY, "- switch tile / close menu");
|
||||
drawBullet("Joystick");
|
||||
drawBullet("- press: open menu or select");
|
||||
drawBullet("Exit Button");
|
||||
drawBullet("- press: switch tile or close menu");
|
||||
}
|
||||
|
||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||
@@ -133,12 +164,21 @@ void InkHUD::TipsApplet::onRender()
|
||||
|
||||
case Tip::ROTATION: {
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Rotation");
|
||||
|
||||
const char *title = "Tip: Rotation";
|
||||
uint16_t h = getWrappedTextHeight(0, width(), title);
|
||||
printWrapped(0, 0, width(), title);
|
||||
|
||||
setFont(fontSmall);
|
||||
if (!settings->joystick.enabled) {
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
||||
"To rotate the display, use the InkHUD menu. Long-press the user button > Options > Rotate.");
|
||||
int16_t cursorY = h + fontSmall.lineHeight();
|
||||
|
||||
const char *body = "To rotate the display, use the InkHUD menu. "
|
||||
"Long-press the user button > Options > Rotate.";
|
||||
|
||||
uint16_t bh = getWrappedTextHeight(0, width(), body);
|
||||
printWrapped(0, cursorY, width(), body);
|
||||
cursorY += bh + (fontSmall.lineHeight() / 2);
|
||||
} else {
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
||||
"To rotate the display, use the InkHUD menu. Press the user button > Options > Rotate.");
|
||||
@@ -159,12 +199,15 @@ void InkHUD::TipsApplet::renderWelcome()
|
||||
{
|
||||
uint16_t padW = X(0.05);
|
||||
|
||||
// Detect portrait orientation
|
||||
bool portrait = height() > width();
|
||||
|
||||
// Block 1 - logo & title
|
||||
// ========================
|
||||
|
||||
// Logo size
|
||||
uint16_t logoWLimit = X(0.3);
|
||||
uint16_t logoHLimit = Y(0.3);
|
||||
uint16_t logoWLimit = portrait ? X(0.5) : X(0.3);
|
||||
uint16_t logoHLimit = portrait ? Y(0.25) : Y(0.3);
|
||||
uint16_t logoW = getLogoWidth(logoWLimit, logoHLimit);
|
||||
uint16_t logoH = getLogoHeight(logoWLimit, logoHLimit);
|
||||
|
||||
@@ -177,7 +220,7 @@ void InkHUD::TipsApplet::renderWelcome()
|
||||
|
||||
// Center the block
|
||||
// Desired effect: equal margin from display edge for logo left and title right
|
||||
int16_t block1Y = Y(0.3);
|
||||
int16_t block1Y = portrait ? Y(0.2) : Y(0.3);
|
||||
int16_t block1CX = X(0.5) + (logoW / 2) - (titleW / 2);
|
||||
int16_t logoCX = block1CX - (logoW / 2) - (padW / 2);
|
||||
int16_t titleCX = block1CX + (titleW / 2) + (padW / 2);
|
||||
@@ -192,7 +235,7 @@ void InkHUD::TipsApplet::renderWelcome()
|
||||
std::string subtitle = "InkHUD";
|
||||
if (width() >= 200)
|
||||
subtitle += " - A Heads-Up Display"; // Future proofing: narrower for tiny display
|
||||
printAt(X(0.5), Y(0.6), subtitle, CENTER, MIDDLE);
|
||||
printAt(X(0.5), portrait ? Y(0.45) : Y(0.6), subtitle, CENTER, MIDDLE);
|
||||
|
||||
// Block 3 - press to continue
|
||||
// ============================
|
||||
@@ -224,26 +267,37 @@ void InkHUD::TipsApplet::onBackground()
|
||||
// While our SystemApplet::handleInput flag is true
|
||||
void InkHUD::TipsApplet::onButtonShortPress()
|
||||
{
|
||||
bool needsRegion = (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET);
|
||||
// If we're prompting the user to pick a region, hand off to the menu
|
||||
if (!tipQueue.empty() && tipQueue.front() == Tip::PICK_REGION) {
|
||||
tipQueue.pop_front();
|
||||
|
||||
// Signal InkHUD to open the menu on Region page
|
||||
inkhud->forceRegionMenu = true;
|
||||
|
||||
// Close tips and open menu
|
||||
sendToBackground();
|
||||
inkhud->openMenu();
|
||||
return;
|
||||
}
|
||||
// Consume current tip
|
||||
tipQueue.pop_front();
|
||||
|
||||
// All tips done
|
||||
if (tipQueue.empty()) {
|
||||
// Record that user has now seen the "tutorial" set of tips
|
||||
// Don't show them on subsequent boots
|
||||
if (settings->tips.firstBoot) {
|
||||
if (settings->tips.firstBoot && !needsRegion) {
|
||||
settings->tips.firstBoot = false;
|
||||
inkhud->persistence->saveSettings();
|
||||
}
|
||||
|
||||
// Close applet, and full refresh to clean the screen
|
||||
// Need to force update, because our request would be ignored otherwise, as we are now background
|
||||
// Close applet and clean the screen
|
||||
sendToBackground();
|
||||
inkhud->forceUpdate(EInk::UpdateTypes::FULL);
|
||||
}
|
||||
|
||||
// More tips left
|
||||
else
|
||||
} else {
|
||||
requestUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// Functions the same as the user button in this instance
|
||||
|
||||
@@ -23,6 +23,7 @@ class TipsApplet : public SystemApplet
|
||||
enum class Tip {
|
||||
WELCOME,
|
||||
FINISH_SETUP,
|
||||
PICK_REGION,
|
||||
SAFE_SHUTDOWN,
|
||||
CUSTOMIZATION,
|
||||
BUTTONS,
|
||||
|
||||
@@ -276,6 +276,15 @@ int InkHUD::Events::beforeDeepSleep(void *unused)
|
||||
return 0; // We agree: deep sleep now
|
||||
}
|
||||
|
||||
// Display an intermediate screen while configuration changes are applied
|
||||
void InkHUD::Events::applyingChanges()
|
||||
{
|
||||
// Bring the logo applet forward with a temporary message
|
||||
for (SystemApplet *sa : inkhud->systemApplets) {
|
||||
sa->onApplyingChanges();
|
||||
}
|
||||
}
|
||||
|
||||
// Callback for rebootObserver
|
||||
// Same as shutdown, without drawing the logoApplet
|
||||
// Makes sure we don't lose message history / InkHUD config
|
||||
|
||||
@@ -29,12 +29,13 @@ class Events
|
||||
|
||||
void onButtonShort(); // User button: short press
|
||||
void onButtonLong(); // User button: long press
|
||||
void onExitShort(); // Exit button: short press
|
||||
void onExitLong(); // Exit button: long press
|
||||
void onNavUp(); // Navigate up
|
||||
void onNavDown(); // Navigate down
|
||||
void onNavLeft(); // Navigate left
|
||||
void onNavRight(); // Navigate right
|
||||
void applyingChanges();
|
||||
void onExitShort(); // Exit button: short press
|
||||
void onExitLong(); // Exit button: long press
|
||||
void onNavUp(); // Navigate up
|
||||
void onNavDown(); // Navigate down
|
||||
void onNavLeft(); // Navigate left
|
||||
void onNavRight(); // Navigate right
|
||||
|
||||
int beforeDeepSleep(void *unused); // Prepare for shutdown
|
||||
int beforeReboot(void *unused); // Prepare for reboot
|
||||
|
||||
@@ -53,6 +53,13 @@ void InkHUD::InkHUD::addApplet(const char *name, Applet *a, bool defaultActive,
|
||||
windowManager->addApplet(name, a, defaultActive, defaultAutoshow, onTile);
|
||||
}
|
||||
|
||||
void InkHUD::InkHUD::notifyApplyingChanges()
|
||||
{
|
||||
if (events) {
|
||||
events->applyingChanges();
|
||||
}
|
||||
}
|
||||
|
||||
// Start InkHUD!
|
||||
// Call this only after you have configured InkHUD
|
||||
void InkHUD::InkHUD::begin()
|
||||
|
||||
@@ -47,6 +47,7 @@ class InkHUD
|
||||
void setDriver(Drivers::EInk *driver);
|
||||
void setDisplayResilience(uint8_t fastPerFull = 5, float stressMultiplier = 2.0);
|
||||
void addApplet(const char *name, Applet *a, bool defaultActive = false, bool defaultAutoshow = false, uint8_t onTile = -1);
|
||||
void notifyApplyingChanges();
|
||||
|
||||
void begin();
|
||||
|
||||
@@ -76,6 +77,9 @@ class InkHUD
|
||||
void rotateJoystick(uint8_t angle = 1); // rotate 90 deg by default
|
||||
void toggleBatteryIcon();
|
||||
|
||||
// Used by TipsApplet to force menu to start on Region selection
|
||||
bool forceRegionMenu = false;
|
||||
|
||||
// Updating the display
|
||||
// - called by various InkHUD components
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ class SystemApplet : public Applet
|
||||
bool lockRequests = false; // - prevent other applets from triggering display updates
|
||||
|
||||
virtual void onReboot() { onShutdown(); } // - handle reboot specially
|
||||
virtual void onApplyingChanges() {}
|
||||
|
||||
// Other system applets may take precedence over our own system applet though
|
||||
// The order an applet is passed to WindowManager::addSystemApplet determines this hierarchy (added earlier = higher rank)
|
||||
|
||||
43
src/main.cpp
43
src/main.cpp
@@ -105,43 +105,6 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#ifdef DEBUG_PARTITION_TABLE
|
||||
#include "esp_partition.h"
|
||||
|
||||
void printPartitionTable()
|
||||
{
|
||||
printf("\n--- Partition Table ---\n");
|
||||
// Print Column Headers
|
||||
printf("| %-16s | %-4s | %-7s | %-10s | %-10s |\n", "Label", "Type", "Subtype", "Offset", "Size");
|
||||
printf("|------------------|------|---------|------------|------------|\n");
|
||||
|
||||
// Create an iterator to find ALL partitions (Type ANY, Subtype ANY)
|
||||
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
|
||||
// Loop through the iterator
|
||||
if (it != NULL) {
|
||||
do {
|
||||
const esp_partition_t *part = esp_partition_get(it);
|
||||
|
||||
// Print details: Label, Type (Hex), Subtype (Hex), Offset (Hex), Size (Hex)
|
||||
printf("| %-16s | 0x%02x | 0x%02x | 0x%08x | 0x%08x |\n", part->label, part->type, part->subtype, part->address,
|
||||
part->size);
|
||||
|
||||
// Move to next partition
|
||||
it = esp_partition_next(it);
|
||||
} while (it != NULL);
|
||||
|
||||
// Release the iterator memory
|
||||
esp_partition_iterator_release(it);
|
||||
} else {
|
||||
printf("No partitions found.\n");
|
||||
}
|
||||
printf("-----------------------\n");
|
||||
}
|
||||
#endif // DEBUG_PARTITION_TABLE
|
||||
#endif // ARCH_ESP32
|
||||
|
||||
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
||||
#include "input/ButtonThread.h"
|
||||
|
||||
@@ -685,11 +648,7 @@ void setup()
|
||||
sensor_detected = true;
|
||||
#endif
|
||||
}
|
||||
#ifdef ARCH_ESP32
|
||||
#ifdef DEBUG_PARTITION_TABLE
|
||||
printPartitionTable();
|
||||
#endif
|
||||
#endif // ARCH_ESP32
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Don't init display if we don't have one or we are waking headless due to a timer event
|
||||
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
|
||||
|
||||
@@ -235,46 +235,22 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
}
|
||||
case meshtastic_AdminMessage_ota_request_tag: {
|
||||
#if defined(ARCH_ESP32)
|
||||
LOG_INFO("OTA Requested");
|
||||
|
||||
if (r->ota_request.ota_hash.size != 32) {
|
||||
suppressRebootBanner = true;
|
||||
sendWarningAndLog("Cannot start OTA: Invalid `ota_hash` provided.");
|
||||
LOG_INFO("OTA Failed: Invalid `ota_hash` provided");
|
||||
break;
|
||||
}
|
||||
|
||||
meshtastic_OTAMode mode = r->ota_request.reboot_ota_mode;
|
||||
const char *mode_name = (mode == METHOD_OTA_BLE ? "BLE" : "WiFi");
|
||||
|
||||
// Check that we have an OTA partition
|
||||
const esp_partition_t *part = MeshtasticOTA::getAppPartition();
|
||||
if (part == NULL) {
|
||||
suppressRebootBanner = true;
|
||||
sendWarningAndLog("Cannot start OTA: Cannot find OTA Loader partition.");
|
||||
break;
|
||||
}
|
||||
|
||||
static esp_app_desc_t app_desc;
|
||||
if (!MeshtasticOTA::getAppDesc(part, &app_desc)) {
|
||||
suppressRebootBanner = true;
|
||||
sendWarningAndLog("Cannot start OTA: Device does have a valid OTA Loader.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!MeshtasticOTA::checkOTACapability(&app_desc, mode)) {
|
||||
suppressRebootBanner = true;
|
||||
sendWarningAndLog("OTA Loader does not support %s", mode_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (MeshtasticOTA::trySwitchToOTA()) {
|
||||
LOG_INFO("OTA Requested");
|
||||
suppressRebootBanner = true;
|
||||
if (screen)
|
||||
screen->startFirmwareUpdateScreen();
|
||||
MeshtasticOTA::saveConfig(&config.network, mode, r->ota_request.ota_hash.bytes);
|
||||
sendWarningAndLog("Rebooting to %s OTA", mode_name);
|
||||
LOG_INFO("Rebooting to WiFi OTA");
|
||||
} else {
|
||||
sendWarningAndLog("Unable to switch to the OTA partition.");
|
||||
LOG_INFO("WIFI OTA Failed");
|
||||
}
|
||||
#endif
|
||||
int s = 1; // Reboot in 1 second, hard coded
|
||||
@@ -1496,43 +1472,15 @@ void AdminModule::handleSendInputEvent(const meshtastic_AdminMessage_InputEvent
|
||||
#endif
|
||||
}
|
||||
|
||||
void AdminModule::sendWarning(const char *format, ...)
|
||||
void AdminModule::sendWarning(const char *message)
|
||||
{
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
if (!cn)
|
||||
return;
|
||||
|
||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
// Format the arguments directly into the notification object
|
||||
vsnprintf(cn->message, sizeof(cn->message), format, args);
|
||||
va_end(args);
|
||||
|
||||
strncpy(cn->message, message, sizeof(cn->message));
|
||||
service->sendClientNotification(cn);
|
||||
}
|
||||
|
||||
void AdminModule::sendWarningAndLog(const char *format, ...)
|
||||
{
|
||||
// We need a temporary buffer to hold the formatted text so we can log it
|
||||
// Using 250 bytes as a safe upper limit for typical text notifications
|
||||
char buf[250];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(buf, sizeof(buf), format, args);
|
||||
va_end(args);
|
||||
|
||||
LOG_WARN(buf);
|
||||
// 2. Call sendWarning
|
||||
// SECURITY NOTE: We pass "%s", buf instead of just 'buf'.
|
||||
// If 'buf' contained a % symbol (e.g. "Battery 50%"), passing it directly
|
||||
// would crash sendWarning. "%s" treats it purely as text.
|
||||
sendWarning("%s", buf);
|
||||
}
|
||||
|
||||
void disableBluetooth()
|
||||
{
|
||||
#if HAS_BLUETOOTH
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
#include "ProtobufModule.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#pragma once
|
||||
#include "ProtobufModule.h"
|
||||
#if HAS_WIFI
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
@@ -73,8 +71,7 @@ class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Obser
|
||||
|
||||
bool messageIsResponse(const meshtastic_AdminMessage *r);
|
||||
bool messageIsRequest(const meshtastic_AdminMessage *r);
|
||||
void sendWarning(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
void sendWarningAndLog(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
void sendWarning(const char *message);
|
||||
};
|
||||
|
||||
static constexpr const char *licensedModeMessage =
|
||||
|
||||
@@ -50,10 +50,9 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
break;
|
||||
}
|
||||
case meshtastic::BluetoothStatus::ConnectionState::CONNECTED: {
|
||||
if (ble_state != connected) {
|
||||
ble_state = connected;
|
||||
PAIRING_LED_starttime = millis();
|
||||
}
|
||||
ble_state = connected;
|
||||
PAIRING_LED_starttime = millis();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
#include "MeshtasticOTA.h"
|
||||
#include "configuration.h"
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <Preferences.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
|
||||
namespace MeshtasticOTA
|
||||
{
|
||||
|
||||
static const char *nvsNamespace = "MeshtasticOTA";
|
||||
static const char *combinedAppProjectName = "MeshtasticOTA";
|
||||
static const char *bleOnlyAppProjectName = "MeshtasticOTA-BLE";
|
||||
static const char *wifiOnlyAppProjectName = "MeshtasticOTA-WiFi";
|
||||
static const char *appProjectName = "MeshtasticOTA";
|
||||
|
||||
static bool updated = false;
|
||||
|
||||
@@ -72,44 +68,21 @@ bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc)
|
||||
LOG_INFO("esp_ota_get_partition_description failed");
|
||||
return false;
|
||||
}
|
||||
if (strcmp(app_desc->project_name, appProjectName) != 0) {
|
||||
LOG_INFO("app_desc->project_name == 0");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkOTACapability(esp_app_desc_t *app_desc, uint8_t method)
|
||||
{
|
||||
// Combined loader supports all (both) transports, BLE and WiFi
|
||||
if (strcmp(app_desc->project_name, combinedAppProjectName) == 0) {
|
||||
LOG_INFO("OTA partition contains combined BLE/WiFi OTA Loader");
|
||||
return true;
|
||||
}
|
||||
if (method == METHOD_OTA_BLE && strcmp(app_desc->project_name, bleOnlyAppProjectName) == 0) {
|
||||
LOG_INFO("OTA partition contains BLE-only OTA Loader");
|
||||
return true;
|
||||
}
|
||||
if (method == METHOD_OTA_WIFI && strcmp(app_desc->project_name, wifiOnlyAppProjectName) == 0) {
|
||||
LOG_INFO("OTA partition contains WiFi-only OTA Loader");
|
||||
return true;
|
||||
}
|
||||
LOG_INFO("OTA partition does not contain a known OTA loader");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool trySwitchToOTA()
|
||||
{
|
||||
const esp_partition_t *part = getAppPartition();
|
||||
|
||||
if (part == NULL) {
|
||||
LOG_WARN("Unable to get app partition in preparation of OTA reboot");
|
||||
esp_app_desc_t app_desc;
|
||||
if (!getAppDesc(part, &app_desc))
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t result = esp_ota_set_boot_partition(part);
|
||||
// Partition and app checks should now be done in the AdminModule before this is called
|
||||
if (result != ESP_OK) {
|
||||
LOG_WARN("Unable to switch to OTA partiton. (Reason %d)", result);
|
||||
if (esp_ota_set_boot_partition(part) != ESP_OK)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,20 +3,12 @@
|
||||
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <Arduino.h>
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
|
||||
#define METHOD_OTA_BLE 1
|
||||
#define METHOD_OTA_WIFI 2
|
||||
|
||||
namespace MeshtasticOTA
|
||||
{
|
||||
void initialize();
|
||||
bool isUpdated();
|
||||
const esp_partition_t *getAppPartition();
|
||||
bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc);
|
||||
bool checkOTACapability(esp_app_desc_t *app_desc, uint8_t method);
|
||||
|
||||
void recoverConfig(meshtastic_Config_NetworkConfig *network);
|
||||
void saveConfig(meshtastic_Config_NetworkConfig *network, meshtastic_OTAMode method, uint8_t *ota_hash);
|
||||
bool trySwitchToOTA();
|
||||
|
||||
@@ -10,8 +10,6 @@ custom_meshtastic_tags = M5Stack
|
||||
|
||||
extends = esp32c6_base
|
||||
board = esp32-c6-devkitc-1
|
||||
board_upload.flash_size = 16MB
|
||||
board_build.partitions = default_16MB.csv
|
||||
;OpenOCD flash method
|
||||
;upload_protocol = esp-builtin
|
||||
;Normal method
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define USB_VID 0x303a
|
||||
#define USB_PID 0x1001
|
||||
|
||||
// The default Wire will be mapped to PMU and RTC
|
||||
static const uint8_t SDA = 18;
|
||||
static const uint8_t SCL = 9;
|
||||
|
||||
// Default SPI will be mapped to Radio
|
||||
static const uint8_t SS = -1;
|
||||
static const uint8_t MOSI = 17;
|
||||
static const uint8_t MISO = 6;
|
||||
static const uint8_t SCK = 8;
|
||||
|
||||
#define SPI_MOSI (39)
|
||||
#define SPI_SCK (41)
|
||||
#define SPI_MISO (38)
|
||||
#define SPI_CS (40)
|
||||
|
||||
#define SDCARD_CS SPI_CS
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
@@ -1,41 +0,0 @@
|
||||
[env:mini-epaper-s3]
|
||||
;custom_meshtastic_hw_model =
|
||||
custom_meshtastic_hw_model_slug = MINI_EPAPER_S3
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = LILYGO Mini ePaper S3 E-Ink
|
||||
custom_meshtastic_images = mini-epaper-s3.svg
|
||||
custom_meshtastic_tags = LilyGo
|
||||
custom_meshtastic_requires_dfu = no
|
||||
|
||||
extends = esp32s3_base
|
||||
board = mini-epaper-s3
|
||||
board_check = true
|
||||
upload_protocol = esptool
|
||||
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags}
|
||||
-I variants/esp32s3/mini-epaper-s3
|
||||
-DMINI_EPAPER_S3
|
||||
-DPRIVATE_HW ; TODO
|
||||
-DUSE_EINK
|
||||
-DEINK_DISPLAY_MODEL=GxEPD2_102
|
||||
-DEINK_WIDTH=80
|
||||
-DEINK_HEIGHT=128
|
||||
; -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk
|
||||
; -DEINK_LIMIT_FASTREFRESH=0 ; How many consecutive fast-refreshes are permitted //20
|
||||
; -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates //30
|
||||
; -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates
|
||||
; -DEINK_HASQUIRK_VICIOUSFASTREFRESH ; Identify that pixels drawn by fast-refresh are harder to clear
|
||||
; -DEINK_LIMIT_GHOSTING_PX=1500 ; (Optional) How much image ghosting is tolerated
|
||||
; -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached.
|
||||
|
||||
lib_deps =
|
||||
${esp32s3_base.lib_deps}
|
||||
# renovate: datasource=custom.pio depName=GxEPD2 packageName=zinggjm/library/GxEPD2
|
||||
zinggjm/GxEPD2@1.6.5
|
||||
;# renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master
|
||||
;https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip
|
||||
# renovate: datasource=custom.pio depName=SensorLib packageName=lewisxhe/library/SensorLib
|
||||
lewisxhe/SensorLib@0.3.3
|
||||
@@ -1,56 +0,0 @@
|
||||
// Display (E-Ink)
|
||||
|
||||
#define PIN_EINK_CS 13
|
||||
#define PIN_EINK_BUSY 10
|
||||
#define PIN_EINK_RES 11
|
||||
#define PIN_EINK_SCLK 14
|
||||
#define PIN_EINK_MOSI 15
|
||||
#define PIN_EINK_DC 12
|
||||
#define PIN_EINK_EN 42
|
||||
|
||||
#define SPI_INTERFACES_COUNT 2
|
||||
#define PIN_SPI1_MISO -1
|
||||
#define PIN_SPI1_MOSI PIN_EINK_MOSI
|
||||
#define PIN_SPI1_SCK PIN_EINK_SCLK
|
||||
|
||||
#define I2C_SDA SDA
|
||||
#define I2C_SCL SCL
|
||||
|
||||
#define BATTERY_PIN 2 // A battery voltage measurement pin, voltage divider connected here to
|
||||
// measure battery voltage ratio of voltage divider = 2.0 (assumption)
|
||||
#define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage.
|
||||
#define ADC_CHANNEL ADC1_GPIO2_CHANNEL
|
||||
|
||||
#define HAS_GPS 0
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#define BUTTON_PIN 3
|
||||
#define BUTTON_NEED_PULLUP
|
||||
#define ALT_BUTTON_PIN 4
|
||||
#define ALT_BUTTON_ACTIVE_LOW true
|
||||
#define ALT_BUTTON_ACTIVE_PULLUP true
|
||||
#define PIN_BUTTON3 0
|
||||
|
||||
// #define HAS_SDCARD 1
|
||||
// #define SDCARD_USE_SOFT_SPI
|
||||
|
||||
// PCF85063 RTC Module
|
||||
#define PCF85063_RTC 0x51
|
||||
#define HAS_RTC 1
|
||||
|
||||
#define USE_SX1262
|
||||
#define LORA_DIO1 5
|
||||
#define LORA_SCK 8
|
||||
#define LORA_MISO 6
|
||||
#define LORA_MOSI 17
|
||||
#define LORA_CS 7 // CS not connected; IO7 is free
|
||||
#define LORA_RESET 21
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 5
|
||||
#define SX126X_BUSY 16
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
#endif
|
||||
Reference in New Issue
Block a user