mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-30 22:50:57 +00:00
Compare commits
34 Commits
develop
...
InkHUD-Imp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
21
.github/workflows/main_matrix.yml
vendored
21
.github/workflows/main_matrix.yml
vendored
@@ -263,17 +263,16 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
base: ${{ github.base_ref }}
|
base: ${{ github.base_ref }}
|
||||||
head: ${{ github.sha }}
|
head: ${{ github.sha }}
|
||||||
# Currently broken (for-loop through EVERY artifact -- rate limiting)
|
- name: Download the old manifests
|
||||||
# - name: Download the old manifests
|
if: github.event_name == 'pull_request_target'
|
||||||
# if: github.event_name == 'pull_request_target'
|
run: gh run download -R "$repo" --name "manifests-$merge_base" --dir manifest-old/
|
||||||
# run: gh run download -R "$repo" --name "manifests-$merge_base" --dir manifest-old/
|
env:
|
||||||
# env:
|
GH_TOKEN: ${{ github.token }}
|
||||||
# GH_TOKEN: ${{ github.token }}
|
merge_base: ${{ env.MERGE_BASE }}
|
||||||
# merge_base: ${{ env.MERGE_BASE }}
|
repo: ${{ github.repository }}
|
||||||
# repo: ${{ github.repository }}
|
- name: Do scan and post comment
|
||||||
# - name: Do scan and post comment
|
if: github.event_name == 'pull_request_target'
|
||||||
# if: github.event_name == 'pull_request_target'
|
run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/
|
||||||
# run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/
|
|
||||||
|
|
||||||
release-artifacts:
|
release-artifacts:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
Submodule protobufs updated: f78b3f0dcc...c474fd3f49
@@ -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
|
// 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()
|
void InkHUD::LogoApplet::onReboot()
|
||||||
{
|
{
|
||||||
bringToForeground();
|
bringToForeground();
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class LogoApplet : public SystemApplet, public concurrency::OSThread
|
|||||||
void onBackground() override;
|
void onBackground() override;
|
||||||
void onShutdown() override;
|
void onShutdown() override;
|
||||||
void onReboot() override;
|
void onReboot() override;
|
||||||
|
void onApplyingChanges();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int32_t runOnce() override;
|
int32_t runOnce() override;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ enum MenuAction {
|
|||||||
STORE_CANNEDMESSAGE_SELECTION,
|
STORE_CANNEDMESSAGE_SELECTION,
|
||||||
SEND_CANNEDMESSAGE,
|
SEND_CANNEDMESSAGE,
|
||||||
SHUTDOWN,
|
SHUTDOWN,
|
||||||
|
BACK,
|
||||||
NEXT_TILE,
|
NEXT_TILE,
|
||||||
TOGGLE_BACKLIGHT,
|
TOGGLE_BACKLIGHT,
|
||||||
TOGGLE_GPS,
|
TOGGLE_GPS,
|
||||||
@@ -36,6 +37,84 @@ enum MenuAction {
|
|||||||
TOGGLE_NOTIFICATIONS,
|
TOGGLE_NOTIFICATIONS,
|
||||||
TOGGLE_INVERT_COLOR,
|
TOGGLE_INVERT_COLOR,
|
||||||
TOGGLE_12H_CLOCK,
|
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
|
} // 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 onRender() override;
|
||||||
|
|
||||||
void show(Tile *t); // Open the menu, onto a user tile
|
void show(Tile *t); // Open the menu, onto a user tile
|
||||||
|
void setStartPage(MenuPage page);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Drivers::LatchingBacklight *backlight = nullptr; // Convenient access to the backlight singleton
|
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 sendText(NodeNum dest, ChannelIndex channel, const char *message); // Send a text message to mesh
|
||||||
void freeCannedMessageResources(); // Clear MenuApplet's canned message processing data
|
void freeCannedMessageResources(); // Clear MenuApplet's canned message processing data
|
||||||
|
|
||||||
|
MenuPage startPageOverride = MenuPage::ROOT;
|
||||||
MenuPage currentPage = MenuPage::ROOT;
|
MenuPage currentPage = MenuPage::ROOT;
|
||||||
MenuPage previousPage = MenuPage::EXIT;
|
MenuPage previousPage = MenuPage::EXIT;
|
||||||
uint8_t cursor = 0; // Which menu item is currently highlighted
|
uint8_t cursor = 0; // Which menu item is currently highlighted
|
||||||
@@ -63,7 +65,14 @@ class MenuApplet : public SystemApplet, public concurrency::OSThread
|
|||||||
|
|
||||||
uint16_t systemInfoPanelHeight = 0; // Need to know before we render
|
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;
|
||||||
|
|
||||||
|
// 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
|
// Data for selecting and sending canned messages via the menu
|
||||||
// Placed into a sub-class for organization only
|
// Placed into a sub-class for organization only
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class MenuItem
|
|||||||
MenuAction action = NO_ACTION;
|
MenuAction action = NO_ACTION;
|
||||||
MenuPage nextPage = EXIT;
|
MenuPage nextPage = EXIT;
|
||||||
bool *checkState = nullptr;
|
bool *checkState = nullptr;
|
||||||
|
bool isHeader = false; // Non-selectable section label
|
||||||
|
|
||||||
// Various constructors, depending on the intended function of the item
|
// Various constructors, depending on the intended function of the item
|
||||||
|
|
||||||
@@ -40,6 +41,12 @@ class MenuItem
|
|||||||
: label(label), action(action), nextPage(nextPage), checkState(checkState)
|
: 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
|
} // namespace NicheGraphics::InkHUD
|
||||||
|
|||||||
@@ -20,10 +20,27 @@ enum MenuPage : uint8_t {
|
|||||||
SEND,
|
SEND,
|
||||||
CANNEDMESSAGE_RECIPIENT, // Select destination for a canned message
|
CANNEDMESSAGE_RECIPIENT, // Select destination for a canned message
|
||||||
OPTIONS,
|
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,
|
APPLETS,
|
||||||
AUTOSHOW,
|
AUTOSHOW,
|
||||||
RECENTS, // Select length of "recentlyActiveSeconds"
|
RECENTS, // Select length of "recentlyActiveSeconds"
|
||||||
EXIT, // Dismiss the menu applet
|
REGION,
|
||||||
|
EXIT, // Dismiss the menu applet
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace NicheGraphics::InkHUD
|
} // namespace NicheGraphics::InkHUD
|
||||||
|
|||||||
@@ -10,34 +10,37 @@ using namespace NicheGraphics;
|
|||||||
|
|
||||||
InkHUD::TipsApplet::TipsApplet()
|
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
|
// Welcome screen
|
||||||
if (settings->tips.firstBoot)
|
if (showTutorialTips)
|
||||||
tipQueue.push_back(Tip::WELCOME);
|
tipQueue.push_back(Tip::WELCOME);
|
||||||
|
|
||||||
// Antenna, region, timezone
|
// Finish setup
|
||||||
// Shown at boot if region not yet set
|
if (needsRegion)
|
||||||
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET)
|
|
||||||
tipQueue.push_back(Tip::FINISH_SETUP);
|
tipQueue.push_back(Tip::FINISH_SETUP);
|
||||||
|
|
||||||
|
// Using the UI
|
||||||
|
if (showTutorialTips) {
|
||||||
|
tipQueue.push_back(Tip::CUSTOMIZATION);
|
||||||
|
tipQueue.push_back(Tip::BUTTONS);
|
||||||
|
}
|
||||||
|
|
||||||
// Shutdown info
|
// Shutdown info
|
||||||
// Shown until user performs one valid shutdown
|
// Shown until user performs one valid shutdown
|
||||||
if (!settings->tips.safeShutdownSeen)
|
if (!settings->tips.safeShutdownSeen)
|
||||||
tipQueue.push_back(Tip::SAFE_SHUTDOWN);
|
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
|
// Catch an incorrect attempt at rotating display
|
||||||
if (config.display.flip_screen)
|
if (config.display.flip_screen)
|
||||||
tipQueue.push_back(Tip::ROTATION);
|
tipQueue.push_back(Tip::ROTATION);
|
||||||
|
|
||||||
// Applet is foreground immediately at boot, but is obscured by LogoApplet, which is also foreground
|
// Region picker
|
||||||
// LogoApplet can be considered to have a higher Z-index, because it is placed before TipsApplet in the systemApplets vector
|
if (needsRegion)
|
||||||
|
tipQueue.push_back(Tip::PICK_REGION);
|
||||||
|
|
||||||
if (!tipQueue.empty())
|
if (!tipQueue.empty())
|
||||||
bringToForeground();
|
bringToForeground();
|
||||||
}
|
}
|
||||||
@@ -51,81 +54,109 @@ void InkHUD::TipsApplet::onRender()
|
|||||||
|
|
||||||
case Tip::FINISH_SETUP: {
|
case Tip::FINISH_SETUP: {
|
||||||
setFont(fontMedium);
|
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);
|
setFont(fontSmall);
|
||||||
int16_t cursorY = fontMedium.lineHeight() * 1.5;
|
int16_t cursorY = h + fontSmall.lineHeight();
|
||||||
printAt(0, cursorY, "- connect antenna");
|
|
||||||
|
|
||||||
cursorY += fontSmall.lineHeight() * 1.2;
|
auto drawBullet = [&](const char *text) {
|
||||||
printAt(0, cursorY, "- connect a client app");
|
uint16_t bh = getWrappedTextHeight(0, width(), text);
|
||||||
|
printWrapped(0, cursorY, width(), text);
|
||||||
|
cursorY += bh + (fontSmall.lineHeight() / 3);
|
||||||
|
};
|
||||||
|
|
||||||
// Only if region not set
|
drawBullet("- connect antenna");
|
||||||
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
drawBullet("- connect a client app");
|
||||||
cursorY += fontSmall.lineHeight() * 1.2;
|
|
||||||
printAt(0, cursorY, "- set region");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only if tz not set
|
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET)
|
||||||
if (!(*config.device.tzdef && config.device.tzdef[0] != 0)) {
|
drawBullet("- set region");
|
||||||
cursorY += fontSmall.lineHeight() * 1.2;
|
|
||||||
printAt(0, cursorY, "- set timezone");
|
|
||||||
}
|
|
||||||
|
|
||||||
cursorY += fontSmall.lineHeight() * 1.5;
|
if (!(*config.device.tzdef && config.device.tzdef[0] != 0))
|
||||||
printAt(0, cursorY, "More info at meshtastic.org");
|
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);
|
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||||
} break;
|
} 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: {
|
case Tip::SAFE_SHUTDOWN: {
|
||||||
setFont(fontMedium);
|
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);
|
setFont(fontSmall);
|
||||||
std::string shutdown;
|
int16_t cursorY = h + fontSmall.lineHeight();
|
||||||
shutdown += "Before removing power, please shut down from InkHUD menu, or a client app. \n";
|
|
||||||
shutdown += "\n";
|
const char *body = "Before removing power, please shut down from InkHUD menu, or a client app.\n\n"
|
||||||
shutdown += "This ensures data is saved.";
|
"This ensures data is saved.";
|
||||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(), shutdown);
|
|
||||||
|
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);
|
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Tip::CUSTOMIZATION: {
|
case Tip::CUSTOMIZATION: {
|
||||||
setFont(fontMedium);
|
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);
|
setFont(fontSmall);
|
||||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
int16_t cursorY = h + fontSmall.lineHeight();
|
||||||
"Configure & control display with the InkHUD menu. Optional features, layout, rotation, and more.");
|
|
||||||
|
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);
|
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Tip::BUTTONS: {
|
case Tip::BUTTONS: {
|
||||||
setFont(fontMedium);
|
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);
|
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) {
|
if (!settings->joystick.enabled) {
|
||||||
printAt(0, cursorY, "User Button");
|
drawBullet("User Button");
|
||||||
cursorY += fontSmall.lineHeight() * 1.2;
|
drawBullet("- short press: next");
|
||||||
printAt(0, cursorY, "- short press: next");
|
drawBullet("- long press: select or open menu");
|
||||||
cursorY += fontSmall.lineHeight() * 1.2;
|
|
||||||
printAt(0, cursorY, "- long press: select / open menu");
|
|
||||||
} else {
|
} else {
|
||||||
printAt(0, cursorY, "Joystick");
|
drawBullet("Joystick");
|
||||||
cursorY += fontSmall.lineHeight() * 1.2;
|
drawBullet("- press: open menu or select");
|
||||||
printAt(0, cursorY, "- open menu / select");
|
drawBullet("Exit Button");
|
||||||
cursorY += fontSmall.lineHeight() * 1.5;
|
drawBullet("- press: switch tile or close menu");
|
||||||
printAt(0, cursorY, "Exit Button");
|
|
||||||
cursorY += fontSmall.lineHeight() * 1.2;
|
|
||||||
printAt(0, cursorY, "- switch tile / close menu");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||||
@@ -133,12 +164,21 @@ void InkHUD::TipsApplet::onRender()
|
|||||||
|
|
||||||
case Tip::ROTATION: {
|
case Tip::ROTATION: {
|
||||||
setFont(fontMedium);
|
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);
|
setFont(fontSmall);
|
||||||
if (!settings->joystick.enabled) {
|
if (!settings->joystick.enabled) {
|
||||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
int16_t cursorY = h + fontSmall.lineHeight();
|
||||||
"To rotate the display, use the InkHUD menu. Long-press the user button > Options > Rotate.");
|
|
||||||
|
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 {
|
} else {
|
||||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
||||||
"To rotate the display, use the InkHUD menu. Press the user button > Options > Rotate.");
|
"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);
|
uint16_t padW = X(0.05);
|
||||||
|
|
||||||
|
// Detect portrait orientation
|
||||||
|
bool portrait = height() > width();
|
||||||
|
|
||||||
// Block 1 - logo & title
|
// Block 1 - logo & title
|
||||||
// ========================
|
// ========================
|
||||||
|
|
||||||
// Logo size
|
// Logo size
|
||||||
uint16_t logoWLimit = X(0.3);
|
uint16_t logoWLimit = portrait ? X(0.5) : X(0.3);
|
||||||
uint16_t logoHLimit = Y(0.3);
|
uint16_t logoHLimit = portrait ? Y(0.25) : Y(0.3);
|
||||||
uint16_t logoW = getLogoWidth(logoWLimit, logoHLimit);
|
uint16_t logoW = getLogoWidth(logoWLimit, logoHLimit);
|
||||||
uint16_t logoH = getLogoHeight(logoWLimit, logoHLimit);
|
uint16_t logoH = getLogoHeight(logoWLimit, logoHLimit);
|
||||||
|
|
||||||
@@ -177,7 +220,7 @@ void InkHUD::TipsApplet::renderWelcome()
|
|||||||
|
|
||||||
// Center the block
|
// Center the block
|
||||||
// Desired effect: equal margin from display edge for logo left and title right
|
// 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 block1CX = X(0.5) + (logoW / 2) - (titleW / 2);
|
||||||
int16_t logoCX = block1CX - (logoW / 2) - (padW / 2);
|
int16_t logoCX = block1CX - (logoW / 2) - (padW / 2);
|
||||||
int16_t titleCX = block1CX + (titleW / 2) + (padW / 2);
|
int16_t titleCX = block1CX + (titleW / 2) + (padW / 2);
|
||||||
@@ -192,7 +235,7 @@ void InkHUD::TipsApplet::renderWelcome()
|
|||||||
std::string subtitle = "InkHUD";
|
std::string subtitle = "InkHUD";
|
||||||
if (width() >= 200)
|
if (width() >= 200)
|
||||||
subtitle += " - A Heads-Up Display"; // Future proofing: narrower for tiny display
|
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
|
// Block 3 - press to continue
|
||||||
// ============================
|
// ============================
|
||||||
@@ -224,26 +267,37 @@ void InkHUD::TipsApplet::onBackground()
|
|||||||
// While our SystemApplet::handleInput flag is true
|
// While our SystemApplet::handleInput flag is true
|
||||||
void InkHUD::TipsApplet::onButtonShortPress()
|
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();
|
tipQueue.pop_front();
|
||||||
|
|
||||||
// All tips done
|
// All tips done
|
||||||
if (tipQueue.empty()) {
|
if (tipQueue.empty()) {
|
||||||
// Record that user has now seen the "tutorial" set of tips
|
// Record that user has now seen the "tutorial" set of tips
|
||||||
// Don't show them on subsequent boots
|
// Don't show them on subsequent boots
|
||||||
if (settings->tips.firstBoot) {
|
if (settings->tips.firstBoot && !needsRegion) {
|
||||||
settings->tips.firstBoot = false;
|
settings->tips.firstBoot = false;
|
||||||
inkhud->persistence->saveSettings();
|
inkhud->persistence->saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close applet, and full refresh to clean the screen
|
// Close applet and clean the screen
|
||||||
// Need to force update, because our request would be ignored otherwise, as we are now background
|
|
||||||
sendToBackground();
|
sendToBackground();
|
||||||
inkhud->forceUpdate(EInk::UpdateTypes::FULL);
|
inkhud->forceUpdate(EInk::UpdateTypes::FULL);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
// More tips left
|
|
||||||
else
|
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions the same as the user button in this instance
|
// Functions the same as the user button in this instance
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class TipsApplet : public SystemApplet
|
|||||||
enum class Tip {
|
enum class Tip {
|
||||||
WELCOME,
|
WELCOME,
|
||||||
FINISH_SETUP,
|
FINISH_SETUP,
|
||||||
|
PICK_REGION,
|
||||||
SAFE_SHUTDOWN,
|
SAFE_SHUTDOWN,
|
||||||
CUSTOMIZATION,
|
CUSTOMIZATION,
|
||||||
BUTTONS,
|
BUTTONS,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
||||||
|
|
||||||
#include "./PositionsApplet.h"
|
#include "./PositionsApplet.h"
|
||||||
#include "NodeDB.h"
|
|
||||||
|
|
||||||
using namespace NicheGraphics;
|
using namespace NicheGraphics;
|
||||||
|
|
||||||
@@ -50,8 +49,8 @@ ProcessMessage InkHUD::PositionsApplet::handleReceived(const meshtastic_MeshPack
|
|||||||
if (!hasPosition)
|
if (!hasPosition)
|
||||||
return ProcessMessage::CONTINUE;
|
return ProcessMessage::CONTINUE;
|
||||||
|
|
||||||
const int8_t hopsAway = getHopsAway(mp);
|
bool hasHopsAway = (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start); // From NodeDB::updateFrom
|
||||||
const bool hasHopsAway = hopsAway >= 0;
|
uint8_t hopsAway = mp.hop_start - mp.hop_limit;
|
||||||
|
|
||||||
// Determine if the position packet would change anything on-screen
|
// Determine if the position packet would change anything on-screen
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|||||||
@@ -276,6 +276,15 @@ int InkHUD::Events::beforeDeepSleep(void *unused)
|
|||||||
return 0; // We agree: deep sleep now
|
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
|
// Callback for rebootObserver
|
||||||
// Same as shutdown, without drawing the logoApplet
|
// Same as shutdown, without drawing the logoApplet
|
||||||
// Makes sure we don't lose message history / InkHUD config
|
// Makes sure we don't lose message history / InkHUD config
|
||||||
|
|||||||
@@ -29,12 +29,13 @@ class Events
|
|||||||
|
|
||||||
void onButtonShort(); // User button: short press
|
void onButtonShort(); // User button: short press
|
||||||
void onButtonLong(); // User button: long press
|
void onButtonLong(); // User button: long press
|
||||||
void onExitShort(); // Exit button: short press
|
void applyingChanges();
|
||||||
void onExitLong(); // Exit button: long press
|
void onExitShort(); // Exit button: short press
|
||||||
void onNavUp(); // Navigate up
|
void onExitLong(); // Exit button: long press
|
||||||
void onNavDown(); // Navigate down
|
void onNavUp(); // Navigate up
|
||||||
void onNavLeft(); // Navigate left
|
void onNavDown(); // Navigate down
|
||||||
void onNavRight(); // Navigate right
|
void onNavLeft(); // Navigate left
|
||||||
|
void onNavRight(); // Navigate right
|
||||||
|
|
||||||
int beforeDeepSleep(void *unused); // Prepare for shutdown
|
int beforeDeepSleep(void *unused); // Prepare for shutdown
|
||||||
int beforeReboot(void *unused); // Prepare for reboot
|
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);
|
windowManager->addApplet(name, a, defaultActive, defaultAutoshow, onTile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InkHUD::InkHUD::notifyApplyingChanges()
|
||||||
|
{
|
||||||
|
if (events) {
|
||||||
|
events->applyingChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start InkHUD!
|
// Start InkHUD!
|
||||||
// Call this only after you have configured InkHUD
|
// Call this only after you have configured InkHUD
|
||||||
void InkHUD::InkHUD::begin()
|
void InkHUD::InkHUD::begin()
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class InkHUD
|
|||||||
void setDriver(Drivers::EInk *driver);
|
void setDriver(Drivers::EInk *driver);
|
||||||
void setDisplayResilience(uint8_t fastPerFull = 5, float stressMultiplier = 2.0);
|
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 addApplet(const char *name, Applet *a, bool defaultActive = false, bool defaultAutoshow = false, uint8_t onTile = -1);
|
||||||
|
void notifyApplyingChanges();
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
|
|
||||||
@@ -76,6 +77,9 @@ class InkHUD
|
|||||||
void rotateJoystick(uint8_t angle = 1); // rotate 90 deg by default
|
void rotateJoystick(uint8_t angle = 1); // rotate 90 deg by default
|
||||||
void toggleBatteryIcon();
|
void toggleBatteryIcon();
|
||||||
|
|
||||||
|
// Used by TipsApplet to force menu to start on Region selection
|
||||||
|
bool forceRegionMenu = false;
|
||||||
|
|
||||||
// Updating the display
|
// Updating the display
|
||||||
// - called by various InkHUD components
|
// - called by various InkHUD components
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class SystemApplet : public Applet
|
|||||||
bool lockRequests = false; // - prevent other applets from triggering display updates
|
bool lockRequests = false; // - prevent other applets from triggering display updates
|
||||||
|
|
||||||
virtual void onReboot() { onShutdown(); } // - handle reboot specially
|
virtual void onReboot() { onShutdown(); } // - handle reboot specially
|
||||||
|
virtual void onApplyingChanges() {}
|
||||||
|
|
||||||
// Other system applets may take precedence over our own system applet though
|
// 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)
|
// The order an applet is passed to WindowManager::addSystemApplet determines this hierarchy (added earlier = higher rank)
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
|
|||||||
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
|
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
|
||||||
// bad.
|
// bad.
|
||||||
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel,
|
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel,
|
||||||
routingModule->getHopLimitForResponse(mp));
|
routingModule->getHopLimitForResponse(mp.hop_start, mp.hop_limit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to)
|
|||||||
assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
|
assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
|
||||||
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
|
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
|
||||||
p->channel = to.channel; // Use the same channel that the request came in on
|
p->channel = to.channel; // Use the same channel that the request came in on
|
||||||
p->hop_limit = routingModule->getHopLimitForResponse(to);
|
p->hop_limit = routingModule->getHopLimitForResponse(to.hop_start, to.hop_limit);
|
||||||
|
|
||||||
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
||||||
p->want_ack = (to.from != 0) ? to.want_ack : false;
|
p->want_ack = (to.from != 0) ? to.want_ack : false;
|
||||||
|
|||||||
@@ -95,8 +95,11 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
|
|||||||
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
|
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
|
||||||
nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) {
|
nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) {
|
||||||
if (airTime->isTxAllowedChannelUtil(true)) {
|
if (airTime->isTxAllowedChannelUtil(true)) {
|
||||||
const int8_t hopsUsed = getHopsAway(*mp, config.lora.hop_limit);
|
// Hops used by the request. If somebody in between running modified firmware modified it, ignore it
|
||||||
if (hopsUsed > (int32_t)(config.lora.hop_limit + 2)) {
|
auto hopStart = mp->hop_start;
|
||||||
|
auto hopLimit = mp->hop_limit;
|
||||||
|
uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
|
||||||
|
if (hopsUsed > config.lora.hop_limit + 2) {
|
||||||
LOG_DEBUG("Skip send NodeInfo: %d hops away is too far away", hopsUsed);
|
LOG_DEBUG("Skip send NodeInfo: %d hops away is too far away", hopsUsed);
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("Heard new node on ch. %d, send NodeInfo and ask for response", mp->channel);
|
LOG_INFO("Heard new node on ch. %d, send NodeInfo and ask for response", mp->channel);
|
||||||
@@ -192,13 +195,15 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
|
|||||||
|
|
||||||
p.rx_time = getValidTime(RTCQualityFromNet); // Record the time the packet arrived from the phone
|
p.rx_time = getValidTime(RTCQualityFromNet); // Record the time the packet arrived from the phone
|
||||||
|
|
||||||
IF_SCREEN(if (p.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && p.decoded.payload.size > 0 &&
|
#if HAS_SCREEN
|
||||||
p.to != NODENUM_BROADCAST && p.to != 0) // DM only
|
if (p.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && p.decoded.payload.size > 0 && p.to != NODENUM_BROADCAST &&
|
||||||
{
|
p.to != 0) // DM only
|
||||||
perhapsDecode(&p);
|
{
|
||||||
const StoredMessage &sm = messageStore.addFromPacket(p);
|
perhapsDecode(&p);
|
||||||
graphics::MessageRenderer::handleNewMessage(nullptr, sm, p); // notify UI
|
const StoredMessage &sm = messageStore.addFromPacket(p);
|
||||||
})
|
graphics::MessageRenderer::handleNewMessage(nullptr, sm, p); // notify UI
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Send the packet into the mesh
|
// Send the packet into the mesh
|
||||||
DEBUG_HEAP_BEFORE;
|
DEBUG_HEAP_BEFORE;
|
||||||
auto a = packetPool.allocCopy(p);
|
auto a = packetPool.allocCopy(p);
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
|||||||
perhapsRebroadcast(p);
|
perhapsRebroadcast(p);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool isRepeated = getHopsAway(*p) == 0;
|
bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit;
|
||||||
// If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again
|
// If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again
|
||||||
if (isRepeated) {
|
if (isRepeated) {
|
||||||
if (!findInTxQueue(p->from, p->id)) {
|
if (!findInTxQueue(p->from, p->id)) {
|
||||||
@@ -101,7 +101,8 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast
|
|||||||
bool wasAlreadyRelayer = wasRelayer(p->relay_node, p->decoded.request_id, p->to);
|
bool wasAlreadyRelayer = wasRelayer(p->relay_node, p->decoded.request_id, p->to);
|
||||||
bool weWereSoleRelayer = false;
|
bool weWereSoleRelayer = false;
|
||||||
bool weWereRelayer = wasRelayer(ourRelayID, p->decoded.request_id, p->to, &weWereSoleRelayer);
|
bool weWereRelayer = wasRelayer(ourRelayID, p->decoded.request_id, p->to, &weWereSoleRelayer);
|
||||||
if ((weWereRelayer && wasAlreadyRelayer) || (getHopsAway(*p) == 0 && weWereSoleRelayer)) {
|
if ((weWereRelayer && wasAlreadyRelayer) ||
|
||||||
|
(p->hop_start != 0 && p->hop_start == p->hop_limit && weWereSoleRelayer)) {
|
||||||
if (origTx->next_hop != p->relay_node) { // Not already set
|
if (origTx->next_hop != p->relay_node) { // Not already set
|
||||||
LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply (was relayer %d we were sole %d)", p->from,
|
LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply (was relayer %d we were sole %d)", p->from,
|
||||||
p->relay_node, wasAlreadyRelayer, weWereSoleRelayer);
|
p->relay_node, wasAlreadyRelayer, weWereSoleRelayer);
|
||||||
|
|||||||
@@ -1549,23 +1549,6 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p)
|
|||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t getHopsAway(const meshtastic_MeshPacket &p, int8_t defaultIfUnknown)
|
|
||||||
{
|
|
||||||
// Firmware prior to 2.3.0 (585805c) lacked a hop_start field. Firmware version 2.5.0 (bf34329) introduced a
|
|
||||||
// bitfield that is always present. Use the presence of the bitfield to determine if the origin's firmware
|
|
||||||
// version is guaranteed to have hop_start populated. Note that this can only be done for decoded packets as
|
|
||||||
// the bitfield is encrypted under the channel encryption key. For encrypted packets, this returns
|
|
||||||
// defaultIfUnknown when hop_start is 0.
|
|
||||||
if (p.hop_start == 0 && !(p.which_payload_variant == meshtastic_MeshPacket_decoded_tag && p.decoded.has_bitfield))
|
|
||||||
return defaultIfUnknown; // Cannot reliably determine the number of hops.
|
|
||||||
|
|
||||||
// Guard against invalid values.
|
|
||||||
if (p.hop_start < p.hop_limit)
|
|
||||||
return defaultIfUnknown;
|
|
||||||
|
|
||||||
return p.hop_start - p.hop_limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
|
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
|
||||||
|
|
||||||
size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
|
size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
|
||||||
@@ -1818,10 +1801,9 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
|||||||
info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
|
info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
|
||||||
|
|
||||||
// If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
|
// If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
|
||||||
const int8_t hopsAway = getHopsAway(mp);
|
if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) {
|
||||||
if (hopsAway >= 0) {
|
|
||||||
info->has_hops_away = true;
|
info->has_hops_away = true;
|
||||||
info->hops_away = hopsAway;
|
info->hops_away = mp.hop_start - mp.hop_limit;
|
||||||
}
|
}
|
||||||
sortMeshDB();
|
sortMeshDB();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,10 +110,6 @@ uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n);
|
|||||||
/// Given a packet, return how many seconds in the past (vs now) it was received
|
/// Given a packet, return how many seconds in the past (vs now) it was received
|
||||||
uint32_t sinceReceived(const meshtastic_MeshPacket *p);
|
uint32_t sinceReceived(const meshtastic_MeshPacket *p);
|
||||||
|
|
||||||
/// Given a packet, return the number of hops used to reach this node.
|
|
||||||
/// Returns defaultIfUnknown if the number of hops couldn't be determined.
|
|
||||||
int8_t getHopsAway(const meshtastic_MeshPacket &p, int8_t defaultIfUnknown = -1);
|
|
||||||
|
|
||||||
enum LoadFileResult {
|
enum LoadFileResult {
|
||||||
// Successfully opened the file
|
// Successfully opened the file
|
||||||
LOAD_SUCCESS = 1,
|
LOAD_SUCCESS = 1,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "ReliableRouter.h"
|
#include "ReliableRouter.h"
|
||||||
#include "Default.h"
|
#include "Default.h"
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "NodeDB.h"
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "memGet.h"
|
#include "memGet.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
@@ -109,12 +108,12 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
|||||||
// If this packet should always be ACKed reliably with want_ack back to the original sender, make sure we
|
// If this packet should always be ACKed reliably with want_ack back to the original sender, make sure we
|
||||||
// do that unconditionally.
|
// do that unconditionally.
|
||||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
|
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
|
||||||
routingModule->getHopLimitForResponse(*p), true);
|
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit), true);
|
||||||
} else if (!p->decoded.request_id && !p->decoded.reply_id) {
|
} else if (!p->decoded.request_id && !p->decoded.reply_id) {
|
||||||
// If it's not an ACK or a reply, send an ACK.
|
// If it's not an ACK or a reply, send an ACK.
|
||||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
|
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
|
||||||
routingModule->getHopLimitForResponse(*p));
|
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
|
||||||
} else if ((getHopsAway(*p) == 0) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
|
} else if ((p->hop_start > 0 && p->hop_start == p->hop_limit) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
|
||||||
// If we received the packet directly from the original sender, send a 0-hop ACK since the original sender
|
// If we received the packet directly from the original sender, send a 0-hop ACK since the original sender
|
||||||
// won't overhear any implicit ACKs. If we received the packet via NextHopRouter, also send a 0-hop ACK to
|
// won't overhear any implicit ACKs. If we received the packet via NextHopRouter, also send a 0-hop ACK to
|
||||||
// stop the immediate relayer's retransmissions.
|
// stop the immediate relayer's retransmissions.
|
||||||
@@ -124,11 +123,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
|||||||
(nodeDB->getMeshNode(p->from) == nullptr || nodeDB->getMeshNode(p->from)->user.public_key.size == 0)) {
|
(nodeDB->getMeshNode(p->from) == nullptr || nodeDB->getMeshNode(p->from)->user.public_key.size == 0)) {
|
||||||
LOG_INFO("PKI packet from unknown node, send PKI_UNKNOWN_PUBKEY");
|
LOG_INFO("PKI packet from unknown node, send PKI_UNKNOWN_PUBKEY");
|
||||||
sendAckNak(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY, getFrom(p), p->id, channels.getPrimaryIndex(),
|
sendAckNak(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY, getFrom(p), p->id, channels.getPrimaryIndex(),
|
||||||
routingModule->getHopLimitForResponse(*p));
|
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
|
||||||
} else {
|
} else {
|
||||||
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
|
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
|
||||||
sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(),
|
sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(),
|
||||||
routingModule->getHopLimitForResponse(*p));
|
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
|
||||||
}
|
}
|
||||||
} else if (p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum()) && p->hop_limit > 0) {
|
} else if (p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum()) && p->hop_limit > 0) {
|
||||||
// No wantAck, but we need to ACK with hop limit of 0 if we were the next hop to stop their retransmissions
|
// No wantAck, but we need to ACK with hop limit of 0 if we were the next hop to stop their retransmissions
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA
|
|||||||
bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
|
bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
|
||||||
{
|
{
|
||||||
// First hop MUST always decrement to prevent retry issues
|
// First hop MUST always decrement to prevent retry issues
|
||||||
if (getHopsAway(*p) == 0) {
|
bool isFirstHop = (p->hop_start != 0 && p->hop_start == p->hop_limit);
|
||||||
|
if (isFirstHop) {
|
||||||
return true; // Always decrement on first hop
|
return true; // Always decrement on first hop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -822,8 +822,6 @@ typedef struct _meshtastic_StoreForwardPlusPlus {
|
|||||||
uint32_t encapsulated_from;
|
uint32_t encapsulated_from;
|
||||||
/* The receive time of the message in question */
|
/* The receive time of the message in question */
|
||||||
uint32_t encapsulated_rxtime;
|
uint32_t encapsulated_rxtime;
|
||||||
/* Used in a LINK_REQUEST to specify the message X spots back from head */
|
|
||||||
uint32_t chain_count;
|
|
||||||
} meshtastic_StoreForwardPlusPlus;
|
} meshtastic_StoreForwardPlusPlus;
|
||||||
|
|
||||||
/* Waypoint message, used to share arbitrary locations across the mesh */
|
/* Waypoint message, used to share arbitrary locations across the mesh */
|
||||||
@@ -1430,7 +1428,7 @@ extern "C" {
|
|||||||
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
|
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
|
||||||
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
||||||
#define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}}
|
#define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}}
|
||||||
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
|
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
|
||||||
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||||
@@ -1462,7 +1460,7 @@ extern "C" {
|
|||||||
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
|
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
|
||||||
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
||||||
#define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}}
|
#define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}}
|
||||||
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
|
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
|
||||||
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||||
@@ -1550,7 +1548,6 @@ extern "C" {
|
|||||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_to_tag 7
|
#define meshtastic_StoreForwardPlusPlus_encapsulated_to_tag 7
|
||||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_from_tag 8
|
#define meshtastic_StoreForwardPlusPlus_encapsulated_from_tag 8
|
||||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_rxtime_tag 9
|
#define meshtastic_StoreForwardPlusPlus_encapsulated_rxtime_tag 9
|
||||||
#define meshtastic_StoreForwardPlusPlus_chain_count_tag 10
|
|
||||||
#define meshtastic_Waypoint_id_tag 1
|
#define meshtastic_Waypoint_id_tag 1
|
||||||
#define meshtastic_Waypoint_latitude_i_tag 2
|
#define meshtastic_Waypoint_latitude_i_tag 2
|
||||||
#define meshtastic_Waypoint_longitude_i_tag 3
|
#define meshtastic_Waypoint_longitude_i_tag 3
|
||||||
@@ -1776,8 +1773,7 @@ X(a, STATIC, SINGULAR, BYTES, message, 5) \
|
|||||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_id, 6) \
|
X(a, STATIC, SINGULAR, UINT32, encapsulated_id, 6) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_to, 7) \
|
X(a, STATIC, SINGULAR, UINT32, encapsulated_to, 7) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_from, 8) \
|
X(a, STATIC, SINGULAR, UINT32, encapsulated_from, 8) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_rxtime, 9) \
|
X(a, STATIC, SINGULAR, UINT32, encapsulated_rxtime, 9)
|
||||||
X(a, STATIC, SINGULAR, UINT32, chain_count, 10)
|
|
||||||
#define meshtastic_StoreForwardPlusPlus_CALLBACK NULL
|
#define meshtastic_StoreForwardPlusPlus_CALLBACK NULL
|
||||||
#define meshtastic_StoreForwardPlusPlus_DEFAULT NULL
|
#define meshtastic_StoreForwardPlusPlus_DEFAULT NULL
|
||||||
|
|
||||||
@@ -2147,7 +2143,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
|||||||
#define meshtastic_QueueStatus_size 23
|
#define meshtastic_QueueStatus_size 23
|
||||||
#define meshtastic_RouteDiscovery_size 256
|
#define meshtastic_RouteDiscovery_size 256
|
||||||
#define meshtastic_Routing_size 259
|
#define meshtastic_Routing_size 259
|
||||||
#define meshtastic_StoreForwardPlusPlus_size 377
|
#define meshtastic_StoreForwardPlusPlus_size 371
|
||||||
#define meshtastic_ToRadio_size 504
|
#define meshtastic_ToRadio_size 504
|
||||||
#define meshtastic_User_size 115
|
#define meshtastic_User_size 115
|
||||||
#define meshtastic_Waypoint_size 165
|
#define meshtastic_Waypoint_size 165
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp,
|
|||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(" Ignoring dummy neighbor info packet (single neighbor with nodeId 0, snr 0)");
|
LOG_DEBUG(" Ignoring dummy neighbor info packet (single neighbor with nodeId 0, snr 0)");
|
||||||
}
|
}
|
||||||
} else if (getHopsAway(mp) == 0) {
|
} else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
|
||||||
LOG_DEBUG("Get or create neighbor: %u with snr %f", mp.from, mp.rx_snr);
|
LOG_DEBUG("Get or create neighbor: %u with snr %f", mp.from, mp.rx_snr);
|
||||||
// If the hopLimit is the same as hopStart, then it is a neighbor
|
// If the hopLimit is the same as hopStart, then it is a neighbor
|
||||||
getOrCreateNeighbor(mp.from, mp.from, 0,
|
getOrCreateNeighbor(mp.from, mp.from, 0,
|
||||||
|
|||||||
@@ -58,11 +58,12 @@ void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketI
|
|||||||
router->sendLocal(p); // we sometimes send directly to the local node
|
router->sendLocal(p); // we sometimes send directly to the local node
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp)
|
uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit)
|
||||||
{
|
{
|
||||||
const int8_t hopsUsed = getHopsAway(mp);
|
if (hopStart != 0) {
|
||||||
if (hopsUsed >= 0) {
|
// Hops used by the request. If somebody in between running modified firmware modified it, ignore it
|
||||||
if (hopsUsed > (int32_t)(config.lora.hop_limit)) {
|
uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
|
||||||
|
if (hopsUsed > config.lora.hop_limit) {
|
||||||
// In event mode, we never want to send packets with more than our default 3 hops.
|
// In event mode, we never want to send packets with more than our default 3 hops.
|
||||||
#if !(EVENTMODE) // This falls through to the default.
|
#if !(EVENTMODE) // This falls through to the default.
|
||||||
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
|
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class RoutingModule : public ProtobufModule<meshtastic_Routing>
|
|||||||
uint8_t hopLimit = 0);
|
uint8_t hopLimit = 0);
|
||||||
|
|
||||||
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
||||||
uint8_t getHopLimitForResponse(const meshtastic_MeshPacket &mp);
|
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Router;
|
friend class Router;
|
||||||
|
|||||||
@@ -21,17 +21,18 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp
|
|||||||
// We only store/display messages destined for us.
|
// We only store/display messages destined for us.
|
||||||
devicestate.rx_text_message = mp;
|
devicestate.rx_text_message = mp;
|
||||||
devicestate.has_rx_text_message = true;
|
devicestate.has_rx_text_message = true;
|
||||||
IF_SCREEN(
|
#if HAS_SCREEN
|
||||||
// Guard against running in MeshtasticUI or with no screen
|
// Guard against running in MeshtasticUI
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
// Store in the central message history
|
// Store in the central message history
|
||||||
const StoredMessage &sm = messageStore.addFromPacket(mp);
|
const StoredMessage &sm = messageStore.addFromPacket(mp);
|
||||||
|
|
||||||
// Pass message to renderer (banner + thread switching + scroll reset)
|
// Pass message to renderer (banner + thread switching + scroll reset)
|
||||||
// Use the global Screen singleton to retrieve the current OLED display
|
// Use the global Screen singleton to retrieve the current OLED display
|
||||||
auto *display = screen ? screen->getDisplayDevice() : nullptr;
|
auto *display = screen ? screen->getDisplayDevice() : nullptr;
|
||||||
graphics::MessageRenderer::handleNewMessage(display, sm, mp);
|
graphics::MessageRenderer::handleNewMessage(display, sm, mp);
|
||||||
})
|
}
|
||||||
|
#endif
|
||||||
// Only trigger screen wake if configuration allows it
|
// Only trigger screen wake if configuration allows it
|
||||||
if (shouldWakeOnReceivedMessage()) {
|
if (shouldWakeOnReceivedMessage()) {
|
||||||
powerFSM.trigger(EVENT_RECEIVED_MSG);
|
powerFSM.trigger(EVENT_RECEIVED_MSG);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "TraceRouteModule.h"
|
#include "TraceRouteModule.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
|
||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
@@ -360,10 +359,10 @@ void TraceRouteModule::insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_Ro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only insert unknown hops if hop_start is valid
|
// Only insert unknown hops if hop_start is valid
|
||||||
const int8_t hopsTaken = getHopsAway(p);
|
if (p.hop_start != 0 && p.hop_limit <= p.hop_start) {
|
||||||
if (hopsTaken >= 0) {
|
uint8_t hopsTaken = p.hop_start - p.hop_limit;
|
||||||
int8_t diff = hopsTaken - *route_count;
|
int8_t diff = hopsTaken - *route_count;
|
||||||
for (int8_t i = 0; i < diff; i++) {
|
for (uint8_t i = 0; i < diff; i++) {
|
||||||
if (*route_count < ROUTE_SIZE) {
|
if (*route_count < ROUTE_SIZE) {
|
||||||
route[*route_count] = NODENUM_BROADCAST; // This will represent an unknown hop
|
route[*route_count] = NODENUM_BROADCAST; // This will represent an unknown hop
|
||||||
*route_count += 1;
|
*route_count += 1;
|
||||||
@@ -371,7 +370,7 @@ void TraceRouteModule::insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_Ro
|
|||||||
}
|
}
|
||||||
// Add unknown SNR values if necessary
|
// Add unknown SNR values if necessary
|
||||||
diff = *route_count - *snr_count;
|
diff = *route_count - *snr_count;
|
||||||
for (int8_t i = 0; i < diff; i++) {
|
for (uint8_t i = 0; i < diff; i++) {
|
||||||
if (*snr_count < ROUTE_SIZE) {
|
if (*snr_count < ROUTE_SIZE) {
|
||||||
snr_list[*snr_count] = INT8_MIN; // This will represent an unknown SNR
|
snr_list[*snr_count] = INT8_MIN; // This will represent an unknown SNR
|
||||||
*snr_count += 1;
|
*snr_count += 1;
|
||||||
|
|||||||
@@ -418,9 +418,8 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp,
|
|||||||
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
||||||
if (mp->rx_snr != 0)
|
if (mp->rx_snr != 0)
|
||||||
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
||||||
const int8_t hopsAway = getHopsAway(*mp);
|
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
||||||
if (hopsAway >= 0) {
|
jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
|
||||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
|
|
||||||
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,9 +450,8 @@ std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPa
|
|||||||
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
|
||||||
if (mp->rx_snr != 0)
|
if (mp->rx_snr != 0)
|
||||||
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
|
||||||
const int8_t hopsAway = getHopsAway(*mp);
|
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
||||||
if (hopsAway >= 0) {
|
jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
|
||||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(hopsAway));
|
|
||||||
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
|
||||||
}
|
}
|
||||||
jsonObj["size"] = new JSONValue((unsigned int)mp->encrypted.size);
|
jsonObj["size"] = new JSONValue((unsigned int)mp->encrypted.size);
|
||||||
|
|||||||
@@ -358,9 +358,8 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp,
|
|||||||
jsonObj["rssi"] = (int)mp->rx_rssi;
|
jsonObj["rssi"] = (int)mp->rx_rssi;
|
||||||
if (mp->rx_snr != 0)
|
if (mp->rx_snr != 0)
|
||||||
jsonObj["snr"] = (float)mp->rx_snr;
|
jsonObj["snr"] = (float)mp->rx_snr;
|
||||||
const int8_t hopsAway = getHopsAway(*mp);
|
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
||||||
if (hopsAway >= 0) {
|
jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
|
||||||
jsonObj["hops_away"] = (unsigned int)(hopsAway);
|
|
||||||
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,9 +393,8 @@ std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPa
|
|||||||
jsonObj["rssi"] = (int)mp->rx_rssi;
|
jsonObj["rssi"] = (int)mp->rx_rssi;
|
||||||
if (mp->rx_snr != 0)
|
if (mp->rx_snr != 0)
|
||||||
jsonObj["snr"] = (float)mp->rx_snr;
|
jsonObj["snr"] = (float)mp->rx_snr;
|
||||||
const int8_t hopsAway = getHopsAway(*mp);
|
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
||||||
if (hopsAway >= 0) {
|
jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
|
||||||
jsonObj["hops_away"] = (unsigned int)(hopsAway);
|
|
||||||
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
||||||
}
|
}
|
||||||
jsonObj["size"] = (unsigned int)mp->encrypted.size;
|
jsonObj["size"] = (unsigned int)mp->encrypted.size;
|
||||||
|
|||||||
Reference in New Issue
Block a user