mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-16 06:47:52 +00:00
Compare commits
54 Commits
sfpp-dev
...
merge-mast
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66cb549817 | ||
|
|
a2ce4c7f18 | ||
|
|
45335532ca | ||
|
|
c351c49a72 | ||
|
|
a5b2d4a9d5 | ||
|
|
7fb95841e4 | ||
|
|
4f1a56d480 | ||
|
|
eaab8f04b5 | ||
|
|
25acce2a8d | ||
|
|
da9d71190f | ||
|
|
1443a32f1b | ||
|
|
9058ccecf9 | ||
|
|
1b83501ee2 | ||
|
|
1b2dc10e77 | ||
|
|
ac571d5dd2 | ||
|
|
ef30fd850d | ||
|
|
3a723ceae8 | ||
|
|
dc36f5df7a | ||
|
|
b9a0015149 | ||
|
|
9673cfb0b2 | ||
|
|
757f7b68d6 | ||
|
|
63aadba526 | ||
|
|
759a972f77 | ||
|
|
d1db4433f4 | ||
|
|
2c68710e8c | ||
|
|
5510dae8d3 | ||
|
|
52fd362720 | ||
|
|
9f8f4471aa | ||
|
|
cf03caff10 | ||
|
|
ac937766cd | ||
|
|
9e215213a7 | ||
|
|
4fbe5356ca | ||
|
|
e899e84ef9 | ||
|
|
69c3c0151f | ||
|
|
2b977b4830 | ||
|
|
b88a8bf968 | ||
|
|
514f8590fe | ||
|
|
cbd40faa89 | ||
|
|
7dd9c8b223 | ||
|
|
3473c32e81 | ||
|
|
33e1f58f6e | ||
|
|
db2224ed0e | ||
|
|
29c5713a7e | ||
|
|
82cf2bf16a | ||
|
|
9dc7ef612e | ||
|
|
ef530db44c | ||
|
|
b2c82bdc41 | ||
|
|
54a928f47f | ||
|
|
33f18659c8 | ||
|
|
3a7093a973 | ||
|
|
a4f6f4515a | ||
|
|
d609d05698 | ||
|
|
83c6161ac6 | ||
|
|
d93d68d31e |
47
.github/workflows/first_time_contributor.yml
vendored
Normal file
47
.github/workflows/first_time_contributor.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Welcome First-Time Contributor
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: opened
|
||||||
|
pull_request_target:
|
||||||
|
types: opened
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
welcome:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write # Required to post comments and labels on issues
|
||||||
|
pull-requests: write # Required to post comments and labels on PRs
|
||||||
|
steps:
|
||||||
|
- uses: plbstl/first-contribution@v4
|
||||||
|
with:
|
||||||
|
labels: first-contribution
|
||||||
|
issue-opened-msg: |
|
||||||
|
### @{fc-author}, Welcome to Meshtastic! :wave:
|
||||||
|
|
||||||
|
Thanks for opening your first issue. If it's helpful, an easy way
|
||||||
|
to get logs is the "Open Serial Monitor" button on the (Web Flasher](https://flasher.meshtastic.org).
|
||||||
|
|
||||||
|
If you have ideas for features, note that we often debate big ideas
|
||||||
|
in the [discussions tab](https://github.com/meshtastic/firmware/discussions/categories/ideas)
|
||||||
|
first. This tracker tends to be for ideas that have community
|
||||||
|
consensus and a clear implementation.
|
||||||
|
|
||||||
|
We're very active [on discord](https://discord.com/invite/meshtastic),
|
||||||
|
especially the \#firmware and \#alphanauts-testing channels. If you'll
|
||||||
|
be around for a while, we'd love to see you there!
|
||||||
|
|
||||||
|
Welcome to the community! :heart:
|
||||||
|
|
||||||
|
pr-opened-msg: |
|
||||||
|
### @{fc-author}, Welcome to Meshtastic!
|
||||||
|
|
||||||
|
Thanks for opening your first pull request. We really appreciate it.
|
||||||
|
|
||||||
|
We discuss work as a team in discord, please join us in the [#firmware channel](https://discord.com/invite/meshtastic).
|
||||||
|
There's a big backlog of patches at the moment. If you have time,
|
||||||
|
please help us with some code review and testing of [other PRs](https://github.com/meshtastic/firmware/pulls)!
|
||||||
|
|
||||||
|
Welcome to the team :smile:
|
||||||
24
.github/workflows/main_matrix.yml
vendored
24
.github/workflows/main_matrix.yml
vendored
@@ -240,6 +240,7 @@ jobs:
|
|||||||
needs: [build]
|
needs: [build]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
if: github.event_name == 'pull_request_target'
|
||||||
with:
|
with:
|
||||||
filter: blob:none # means we download all the git history but none of the commit (except ones with checkout like the head)
|
filter: blob:none # means we download all the git history but none of the commit (except ones with checkout like the head)
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -253,19 +254,26 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v6
|
||||||
id: upload-manifest
|
id: upload-manifest
|
||||||
with:
|
with:
|
||||||
name: manifests-all
|
name: manifests-${{ github.sha }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
path: |
|
path: manifests-new/*.mt.json
|
||||||
manifests-new/*.mt.json
|
|
||||||
- name: Find the merge base
|
- name: Find the merge base
|
||||||
|
if: github.event_name == 'pull_request_target'
|
||||||
run: echo "MERGE_BASE=$(git merge-base "origin/$base" "$head")" >> $GITHUB_ENV
|
run: echo "MERGE_BASE=$(git merge-base "origin/$base" "$head")" >> $GITHUB_ENV
|
||||||
env:
|
env:
|
||||||
base: ${{ github.base_ref }}
|
base: ${{ github.base_ref }}
|
||||||
head: ${{ github.head_ref }}
|
head: ${{ github.sha }}
|
||||||
- name: Download the old manifests
|
# Currently broken (for-loop through EVERY artifact -- rate limiting)
|
||||||
run: gh run download -R ${{ github.repository }} --commit ${{ env.MERGE_BASE }} --name manifests-all --dir manifest-old/
|
# - name: Download the old manifests
|
||||||
- name: Do scan and post comment
|
# if: github.event_name == 'pull_request_target'
|
||||||
run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/
|
# run: gh run download -R "$repo" --name "manifests-$merge_base" --dir manifest-old/
|
||||||
|
# env:
|
||||||
|
# GH_TOKEN: ${{ github.token }}
|
||||||
|
# merge_base: ${{ env.MERGE_BASE }}
|
||||||
|
# repo: ${{ github.repository }}
|
||||||
|
# - name: Do scan and post comment
|
||||||
|
# if: github.event_name == 'pull_request_target'
|
||||||
|
# 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
|
||||||
|
|||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -41,3 +41,12 @@ src/mesh/raspihttp/private_key.pem
|
|||||||
|
|
||||||
# Ignore logo (set at build time with platformio-custom.py)
|
# Ignore logo (set at build time with platformio-custom.py)
|
||||||
data/boot/logo.*
|
data/boot/logo.*
|
||||||
|
|
||||||
|
# pioarduino platform
|
||||||
|
managed_components/*
|
||||||
|
arduino-lib-builder*
|
||||||
|
dependencies.lock
|
||||||
|
idf_component.yml
|
||||||
|
CMakeLists.txt
|
||||||
|
sdkconfig.*
|
||||||
|
.dummy/*
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ plugins:
|
|||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.495
|
- checkov@3.2.496
|
||||||
- renovate@42.64.1
|
- renovate@42.66.14
|
||||||
- prettier@3.7.4
|
- prettier@3.7.4
|
||||||
- trufflehog@3.92.3
|
- trufflehog@3.92.4
|
||||||
- yamllint@1.37.1
|
- yamllint@1.37.1
|
||||||
- bandit@1.9.2
|
- bandit@1.9.2
|
||||||
- trivy@0.68.2
|
- trivy@0.68.2
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ rm -f $BUILDDIR/firmware*
|
|||||||
export APP_VERSION=$VERSION
|
export APP_VERSION=$VERSION
|
||||||
|
|
||||||
basename=firmware-$1-$VERSION
|
basename=firmware-$1-$VERSION
|
||||||
|
ota_basename=${basename}-ota
|
||||||
|
|
||||||
pio run --environment $1 -t mtjson # -v
|
pio run --environment $1 -t mtjson # -v
|
||||||
|
|
||||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||||
|
|
||||||
echo "Copying NRF52 dfu (OTA) file"
|
echo "Copying NRF52 dfu (OTA) file"
|
||||||
cp $BUILDDIR/$basename.zip $OUTDIR/$basename.zip
|
cp $BUILDDIR/$basename.zip $OUTDIR/$ota_basename.zip
|
||||||
|
|
||||||
echo "Copying NRF52 UF2 file"
|
echo "Copying NRF52 UF2 file"
|
||||||
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
||||||
|
|||||||
@@ -87,9 +87,6 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
<release version="2.7.18" date="2025-12-20">
|
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.18</url>
|
|
||||||
</release>
|
|
||||||
<release version="2.7.17" date="2025-11-28">
|
<release version="2.7.17" date="2025-11-28">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.17</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.17</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ lfsbin = f"{progname.replace('firmware-', 'littlefs-')}.bin"
|
|||||||
|
|
||||||
def manifest_gather(source, target, env):
|
def manifest_gather(source, target, env):
|
||||||
out = []
|
out = []
|
||||||
|
board_platform = env.BoardConfig().get("platform")
|
||||||
|
needs_ota_suffix = board_platform == "nordicnrf52"
|
||||||
check_paths = [
|
check_paths = [
|
||||||
progname,
|
progname,
|
||||||
f"{progname}.elf",
|
f"{progname}.elf",
|
||||||
@@ -32,8 +34,11 @@ def manifest_gather(source, target, env):
|
|||||||
for p in check_paths:
|
for p in check_paths:
|
||||||
f = env.File(env.subst(f"$BUILD_DIR/{p}"))
|
f = env.File(env.subst(f"$BUILD_DIR/{p}"))
|
||||||
if f.exists():
|
if f.exists():
|
||||||
|
manifest_name = p
|
||||||
|
if needs_ota_suffix and p == f"{progname}.zip":
|
||||||
|
manifest_name = f"{progname}-ota.zip"
|
||||||
d = {
|
d = {
|
||||||
"name": p,
|
"name": manifest_name,
|
||||||
"md5": f.get_content_hash(), # Returns MD5 hash
|
"md5": f.get_content_hash(), # Returns MD5 hash
|
||||||
"bytes": f.get_size() # Returns file size in bytes
|
"bytes": f.get_size() # Returns file size in bytes
|
||||||
}
|
}
|
||||||
|
|||||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,9 +1,3 @@
|
|||||||
meshtasticd (2.7.18.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
* Version 2.7.18
|
|
||||||
|
|
||||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Sat, 20 Dec 2025 15:47:25 +0000
|
|
||||||
|
|
||||||
meshtasticd (2.7.17.0) unstable; urgency=medium
|
meshtasticd (2.7.17.0) unstable; urgency=medium
|
||||||
|
|
||||||
* Version 2.7.17
|
* Version 2.7.17
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ monitor_speed = 115200
|
|||||||
monitor_filters = direct
|
monitor_filters = direct
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
||||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/2887bf4a19f64d92c984dcc8fd5ca7429e425e4a.zip
|
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/b34c6817c25d6faabb3a8a162b5d14fb75395433.zip
|
||||||
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
||||||
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
||||||
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
||||||
@@ -119,7 +119,7 @@ lib_deps =
|
|||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||||
https://github.com/meshtastic/device-ui/archive/862ed040c4ab44f0dfbbe492691f144886102588.zip
|
https://github.com/meshtastic/device-ui/archive/940ba8570f59c59c3508643f4d72840de716ce20.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
|
|||||||
Submodule protobufs updated: c474fd3f49...f78b3f0dcc
@@ -8,6 +8,7 @@
|
|||||||
#include "graphics/draw/UIRenderer.h"
|
#include "graphics/draw/UIRenderer.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshtastic/config.pb.h"
|
#include "meshtastic/config.pb.h"
|
||||||
|
#include "modules/ExternalNotificationModule.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
#include <graphics/images.h>
|
#include <graphics/images.h>
|
||||||
@@ -56,7 +57,6 @@ void decomposeTime(uint32_t rtc_sec, int &hour, int &minute, int &second)
|
|||||||
|
|
||||||
// === Shared External State ===
|
// === Shared External State ===
|
||||||
bool hasUnreadMessage = false;
|
bool hasUnreadMessage = false;
|
||||||
bool isMuted = false;
|
|
||||||
ScreenResolution currentResolution = ScreenResolution::Low;
|
ScreenResolution currentResolution = ScreenResolution::Low;
|
||||||
|
|
||||||
// === Internal State ===
|
// === Internal State ===
|
||||||
@@ -306,7 +306,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
}
|
}
|
||||||
display->drawXbm(iconX, iconY, mail_width, mail_height, mail);
|
display->drawXbm(iconX, iconY, mail_width, mail_height, mail);
|
||||||
}
|
}
|
||||||
} else if (isMuted) {
|
} else if (externalNotificationModule->getMute()) {
|
||||||
if (currentResolution == ScreenResolution::High) {
|
if (currentResolution == ScreenResolution::High) {
|
||||||
int iconX = iconRightEdge - mute_symbol_big_width;
|
int iconX = iconRightEdge - mute_symbol_big_width;
|
||||||
int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2;
|
int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2;
|
||||||
@@ -325,7 +325,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
int iconX = iconRightEdge - mute_symbol_width;
|
int iconX = iconRightEdge - mute_symbol_width;
|
||||||
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
|
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
|
||||||
|
|
||||||
if (isInverted) {
|
if (isInverted && !force_no_invert) {
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
display->fillRect(iconX - 1, iconY - 1, mute_symbol_width + 2, mute_symbol_height + 2);
|
display->fillRect(iconX - 1, iconY - 1, mute_symbol_width + 2, mute_symbol_height + 2);
|
||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
@@ -383,7 +383,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
|
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
|
||||||
display->drawXbm(iconX, iconY, mail_width, mail_height, mail);
|
display->drawXbm(iconX, iconY, mail_width, mail_height, mail);
|
||||||
}
|
}
|
||||||
} else if (isMuted) {
|
} else if (externalNotificationModule->getMute()) {
|
||||||
if (currentResolution == ScreenResolution::High) {
|
if (currentResolution == ScreenResolution::High) {
|
||||||
int iconX = iconRightEdge - mute_symbol_big_width;
|
int iconX = iconRightEdge - mute_symbol_big_width;
|
||||||
int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2;
|
int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2;
|
||||||
@@ -470,18 +470,49 @@ bool isAllowedPunctuation(char c)
|
|||||||
return allowed.find(c) != std::string::npos;
|
return allowed.find(c) != std::string::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void replaceAll(std::string &s, const std::string &from, const std::string &to)
|
||||||
|
{
|
||||||
|
if (from.empty())
|
||||||
|
return;
|
||||||
|
size_t pos = 0;
|
||||||
|
while ((pos = s.find(from, pos)) != std::string::npos) {
|
||||||
|
s.replace(pos, from.size(), to);
|
||||||
|
pos += to.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string sanitizeString(const std::string &input)
|
std::string sanitizeString(const std::string &input)
|
||||||
{
|
{
|
||||||
std::string output;
|
std::string output;
|
||||||
bool inReplacement = false;
|
bool inReplacement = false;
|
||||||
|
|
||||||
for (char c : input) {
|
// Make a mutable copy so we can normalize UTF-8 “smart punctuation” into ASCII first.
|
||||||
if (std::isalnum(static_cast<unsigned char>(c)) || isAllowedPunctuation(c)) {
|
std::string s = input;
|
||||||
|
|
||||||
|
// Curly single quotes: ‘ ’
|
||||||
|
replaceAll(s, "\xE2\x80\x98", "'"); // U+2018
|
||||||
|
replaceAll(s, "\xE2\x80\x99", "'"); // U+2019
|
||||||
|
|
||||||
|
// Curly double quotes: “ ”
|
||||||
|
replaceAll(s, "\xE2\x80\x9C", "\""); // U+201C
|
||||||
|
replaceAll(s, "\xE2\x80\x9D", "\""); // U+201D
|
||||||
|
|
||||||
|
// En dash / Em dash: – —
|
||||||
|
replaceAll(s, "\xE2\x80\x93", "-"); // U+2013
|
||||||
|
replaceAll(s, "\xE2\x80\x94", "-"); // U+2014
|
||||||
|
|
||||||
|
// Non-breaking space
|
||||||
|
replaceAll(s, "\xC2\xA0", " "); // U+00A0
|
||||||
|
|
||||||
|
// Now do your original sanitize pass over the normalized string.
|
||||||
|
for (unsigned char uc : s) {
|
||||||
|
char c = static_cast<char>(uc);
|
||||||
|
if (std::isalnum(uc) || isAllowedPunctuation(c)) {
|
||||||
output += c;
|
output += c;
|
||||||
inReplacement = false;
|
inReplacement = false;
|
||||||
} else {
|
} else {
|
||||||
if (!inReplacement) {
|
if (!inReplacement) {
|
||||||
output += 0xbf; // ISO-8859-1 for inverted question mark
|
output += static_cast<char>(0xBF); // ISO-8859-1 for inverted question mark
|
||||||
inReplacement = true;
|
inReplacement = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ namespace graphics
|
|||||||
|
|
||||||
// Shared state (declare inside namespace)
|
// Shared state (declare inside namespace)
|
||||||
extern bool hasUnreadMessage;
|
extern bool hasUnreadMessage;
|
||||||
extern bool isMuted;
|
|
||||||
enum class ScreenResolution : uint8_t { UltraLow = 0, Low = 1, High = 2 };
|
enum class ScreenResolution : uint8_t { UltraLow = 0, Low = 1, High = 2 };
|
||||||
extern ScreenResolution currentResolution;
|
extern ScreenResolution currentResolution;
|
||||||
ScreenResolution determineScreenResolution(int16_t screenheight, int16_t screenwidth);
|
ScreenResolution determineScreenResolution(int16_t screenheight, int16_t screenwidth);
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
#include "mesh/MeshTypes.h"
|
#include "mesh/MeshTypes.h"
|
||||||
#include "modules/AdminModule.h"
|
#include "modules/AdminModule.h"
|
||||||
#include "modules/CannedMessageModule.h"
|
#include "modules/CannedMessageModule.h"
|
||||||
|
#include "modules/ExternalNotificationModule.h"
|
||||||
#include "modules/KeyVerificationModule.h"
|
#include "modules/KeyVerificationModule.h"
|
||||||
|
|
||||||
#include "modules/TraceRouteModule.h"
|
#include "modules/TraceRouteModule.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -843,12 +843,21 @@ void menuHandler::messageViewModeMenu()
|
|||||||
|
|
||||||
void menuHandler::homeBaseMenu()
|
void menuHandler::homeBaseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, Backlight, Position, Preset, Freetext, Sleep, enumEnd };
|
enum optionsNumbers { Back, Mute, Backlight, Position, Preset, Freetext, Sleep, enumEnd };
|
||||||
|
|
||||||
static const char *optionsArray[enumEnd] = {"Back"};
|
static const char *optionsArray[enumEnd] = {"Back"};
|
||||||
static int optionsEnumArray[enumEnd] = {Back};
|
static int optionsEnumArray[enumEnd] = {Back};
|
||||||
int options = 1;
|
int options = 1;
|
||||||
|
|
||||||
|
if (moduleConfig.external_notification.enabled && externalNotificationModule &&
|
||||||
|
config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DISABLED) {
|
||||||
|
if (!externalNotificationModule->getMute()) {
|
||||||
|
optionsArray[options] = "Temporarily Mute";
|
||||||
|
} else {
|
||||||
|
optionsArray[options] = "Unmute";
|
||||||
|
}
|
||||||
|
optionsEnumArray[options++] = Mute;
|
||||||
|
}
|
||||||
#if defined(PIN_EINK_EN) || defined(PCA_PIN_EINK_EN)
|
#if defined(PIN_EINK_EN) || defined(PCA_PIN_EINK_EN)
|
||||||
optionsArray[options] = "Toggle Backlight";
|
optionsArray[options] = "Toggle Backlight";
|
||||||
optionsEnumArray[options++] = Backlight;
|
optionsEnumArray[options++] = Backlight;
|
||||||
@@ -872,7 +881,13 @@ void menuHandler::homeBaseMenu()
|
|||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
if (selected == Backlight) {
|
if (selected == Mute) {
|
||||||
|
if (moduleConfig.external_notification.enabled && externalNotificationModule) {
|
||||||
|
externalNotificationModule->setMute(!externalNotificationModule->getMute());
|
||||||
|
IF_SCREEN(if (!externalNotificationModule->getMute()) externalNotificationModule->stopNow();)
|
||||||
|
}
|
||||||
|
} else if (selected == Backlight) {
|
||||||
|
screen->setOn(false);
|
||||||
#if defined(PIN_EINK_EN)
|
#if defined(PIN_EINK_EN)
|
||||||
if (uiconfig.screen_brightness == 1) {
|
if (uiconfig.screen_brightness == 1) {
|
||||||
uiconfig.screen_brightness = 0;
|
uiconfig.screen_brightness = 0;
|
||||||
@@ -949,6 +964,7 @@ void menuHandler::systemBaseMenu()
|
|||||||
|
|
||||||
optionsArray[options] = "Notifications";
|
optionsArray[options] = "Notifications";
|
||||||
optionsEnumArray[options++] = Notifications;
|
optionsEnumArray[options++] = Notifications;
|
||||||
|
|
||||||
optionsArray[options] = "Display Options";
|
optionsArray[options] = "Display Options";
|
||||||
optionsEnumArray[options++] = ScreenOptions;
|
optionsEnumArray[options++] = ScreenOptions;
|
||||||
|
|
||||||
@@ -985,7 +1001,7 @@ void menuHandler::systemBaseMenu()
|
|||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
if (selected == Notifications) {
|
if (selected == Notifications) {
|
||||||
menuHandler::menuQueue = menuHandler::notifications_menu;
|
menuHandler::menuQueue = menuHandler::buzzermodemenupicker;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
} else if (selected == ScreenOptions) {
|
} else if (selected == ScreenOptions) {
|
||||||
menuHandler::menuQueue = menuHandler::screen_options_menu;
|
menuHandler::menuQueue = menuHandler::screen_options_menu;
|
||||||
@@ -1092,11 +1108,23 @@ void menuHandler::favoriteBaseMenu()
|
|||||||
|
|
||||||
void menuHandler::positionBaseMenu()
|
void menuHandler::positionBaseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, GPSToggle, GPSFormat, CompassMenu, CompassCalibrate, enumEnd };
|
enum optionsNumbers {
|
||||||
|
Back,
|
||||||
|
GPSToggle,
|
||||||
|
GPSFormat,
|
||||||
|
CompassMenu,
|
||||||
|
CompassCalibrate,
|
||||||
|
GPSSmartPosition,
|
||||||
|
GPSUpdateInterval,
|
||||||
|
GPSPositionBroadcast,
|
||||||
|
enumEnd
|
||||||
|
};
|
||||||
|
|
||||||
static const char *optionsArray[enumEnd] = {"Back", "GPS Toggle", "GPS Format", "Compass"};
|
static const char *optionsArray[enumEnd] = {
|
||||||
static int optionsEnumArray[enumEnd] = {Back, GPSToggle, GPSFormat, CompassMenu};
|
"Back", "On/Off Toggle", "Format", "Smart Position", "Update Interval", "Broadcast Interval", "Compass"};
|
||||||
int options = 4;
|
static int optionsEnumArray[enumEnd] = {
|
||||||
|
Back, GPSToggle, GPSFormat, GPSSmartPosition, GPSUpdateInterval, GPSPositionBroadcast, CompassMenu};
|
||||||
|
int options = 7;
|
||||||
|
|
||||||
if (accelerometerThread) {
|
if (accelerometerThread) {
|
||||||
optionsArray[options] = "Compass Calibrate";
|
optionsArray[options] = "Compass Calibrate";
|
||||||
@@ -1104,7 +1132,7 @@ void menuHandler::positionBaseMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Position Action";
|
bannerOptions.message = "GPS Action";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
@@ -1120,6 +1148,15 @@ void menuHandler::positionBaseMenu()
|
|||||||
screen->runNow();
|
screen->runNow();
|
||||||
} else if (selected == CompassCalibrate) {
|
} else if (selected == CompassCalibrate) {
|
||||||
accelerometerThread->calibrate(30);
|
accelerometerThread->calibrate(30);
|
||||||
|
} else if (selected == GPSSmartPosition) {
|
||||||
|
menuQueue = gps_smart_position_menu;
|
||||||
|
screen->runNow();
|
||||||
|
} else if (selected == GPSUpdateInterval) {
|
||||||
|
menuQueue = gps_update_interval_menu;
|
||||||
|
screen->runNow();
|
||||||
|
} else if (selected == GPSPositionBroadcast) {
|
||||||
|
menuQueue = gps_position_broadcast_menu;
|
||||||
|
screen->runNow();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
@@ -1346,6 +1383,217 @@ void menuHandler::GPSFormatMenu()
|
|||||||
bannerOptions.InitialSelected = uiconfig.gps_format + 1;
|
bannerOptions.InitialSelected = uiconfig.gps_format + 1;
|
||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void menuHandler::GPSSmartPositionMenu()
|
||||||
|
{
|
||||||
|
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
|
||||||
|
BannerOverlayOptions bannerOptions;
|
||||||
|
bannerOptions.message = "Toggle Smart Position";
|
||||||
|
if (currentResolution == ScreenResolution::UltraLow) {
|
||||||
|
bannerOptions.message = "Smrt Postn";
|
||||||
|
}
|
||||||
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
|
bannerOptions.optionsCount = 3;
|
||||||
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
|
if (selected == 0) {
|
||||||
|
menuQueue = position_base_menu;
|
||||||
|
screen->runNow();
|
||||||
|
} else if (selected == 1) {
|
||||||
|
config.position.position_broadcast_smart_enabled = true;
|
||||||
|
saveUIConfig();
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||||
|
} else if (selected == 2) {
|
||||||
|
config.position.position_broadcast_smart_enabled = false;
|
||||||
|
saveUIConfig();
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bannerOptions.InitialSelected = config.position.position_broadcast_smart_enabled ? 1 : 2;
|
||||||
|
screen->showOverlayBanner(bannerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void menuHandler::GPSUpdateIntervalMenu()
|
||||||
|
{
|
||||||
|
static const char *optionsArray[] = {"Back", "8 seconds", "20 seconds", "40 seconds", "1 minute", "80 seconds",
|
||||||
|
"2 minutes", "5 minutes", "10 minutes", "15 minutes", "30 minutes", "1 hour",
|
||||||
|
"6 hours", "12 hours", "24 hours", "At Boot Only"};
|
||||||
|
BannerOverlayOptions bannerOptions;
|
||||||
|
bannerOptions.message = "Update Interval";
|
||||||
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
|
bannerOptions.optionsCount = 16;
|
||||||
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
|
if (selected == 0) {
|
||||||
|
menuQueue = position_base_menu;
|
||||||
|
screen->runNow();
|
||||||
|
} else if (selected == 1) {
|
||||||
|
config.position.gps_update_interval = 8;
|
||||||
|
} else if (selected == 2) {
|
||||||
|
config.position.gps_update_interval = 20;
|
||||||
|
} else if (selected == 3) {
|
||||||
|
config.position.gps_update_interval = 40;
|
||||||
|
} else if (selected == 4) {
|
||||||
|
config.position.gps_update_interval = 60;
|
||||||
|
} else if (selected == 5) {
|
||||||
|
config.position.gps_update_interval = 80;
|
||||||
|
} else if (selected == 6) {
|
||||||
|
config.position.gps_update_interval = 120;
|
||||||
|
} else if (selected == 7) {
|
||||||
|
config.position.gps_update_interval = 300;
|
||||||
|
} else if (selected == 8) {
|
||||||
|
config.position.gps_update_interval = 600;
|
||||||
|
} else if (selected == 9) {
|
||||||
|
config.position.gps_update_interval = 900;
|
||||||
|
} else if (selected == 10) {
|
||||||
|
config.position.gps_update_interval = 1800;
|
||||||
|
} else if (selected == 11) {
|
||||||
|
config.position.gps_update_interval = 3600;
|
||||||
|
} else if (selected == 12) {
|
||||||
|
config.position.gps_update_interval = 21600;
|
||||||
|
} else if (selected == 13) {
|
||||||
|
config.position.gps_update_interval = 43200;
|
||||||
|
} else if (selected == 14) {
|
||||||
|
config.position.gps_update_interval = 86400;
|
||||||
|
} else if (selected == 15) {
|
||||||
|
config.position.gps_update_interval = 2147483647; // At Boot Only
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected != 0) {
|
||||||
|
saveUIConfig();
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.position.gps_update_interval == 8) {
|
||||||
|
bannerOptions.InitialSelected = 1;
|
||||||
|
} else if (config.position.gps_update_interval == 20) {
|
||||||
|
bannerOptions.InitialSelected = 2;
|
||||||
|
} else if (config.position.gps_update_interval == 40) {
|
||||||
|
bannerOptions.InitialSelected = 3;
|
||||||
|
} else if (config.position.gps_update_interval == 60) {
|
||||||
|
bannerOptions.InitialSelected = 4;
|
||||||
|
} else if (config.position.gps_update_interval == 80) {
|
||||||
|
bannerOptions.InitialSelected = 5;
|
||||||
|
} else if (config.position.gps_update_interval == 120) {
|
||||||
|
bannerOptions.InitialSelected = 6;
|
||||||
|
} else if (config.position.gps_update_interval == 300) {
|
||||||
|
bannerOptions.InitialSelected = 7;
|
||||||
|
} else if (config.position.gps_update_interval == 600) {
|
||||||
|
bannerOptions.InitialSelected = 8;
|
||||||
|
} else if (config.position.gps_update_interval == 900) {
|
||||||
|
bannerOptions.InitialSelected = 9;
|
||||||
|
} else if (config.position.gps_update_interval == 1800) {
|
||||||
|
bannerOptions.InitialSelected = 10;
|
||||||
|
} else if (config.position.gps_update_interval == 3600) {
|
||||||
|
bannerOptions.InitialSelected = 11;
|
||||||
|
} else if (config.position.gps_update_interval == 21600) {
|
||||||
|
bannerOptions.InitialSelected = 12;
|
||||||
|
} else if (config.position.gps_update_interval == 43200) {
|
||||||
|
bannerOptions.InitialSelected = 13;
|
||||||
|
} else if (config.position.gps_update_interval == 86400) {
|
||||||
|
bannerOptions.InitialSelected = 14;
|
||||||
|
} else if (config.position.gps_update_interval == 2147483647) { // At Boot Only
|
||||||
|
bannerOptions.InitialSelected = 15;
|
||||||
|
} else {
|
||||||
|
bannerOptions.InitialSelected = 0;
|
||||||
|
}
|
||||||
|
screen->showOverlayBanner(bannerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void menuHandler::GPSPositionBroadcastMenu()
|
||||||
|
{
|
||||||
|
static const char *optionsArray[] = {"Back", "1 minute", "90 seconds", "5 minutes", "15 minutes", "1 hour",
|
||||||
|
"2 hours", "3 hours", "4 hours", "5 hours", "6 hours", "12 hours",
|
||||||
|
"18 hours", "24 hours", "36 hours", "48 hours", "72 hours"};
|
||||||
|
BannerOverlayOptions bannerOptions;
|
||||||
|
bannerOptions.message = "Broadcast Interval";
|
||||||
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
|
bannerOptions.optionsCount = 17;
|
||||||
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
|
if (selected == 0) {
|
||||||
|
menuQueue = position_base_menu;
|
||||||
|
screen->runNow();
|
||||||
|
} else if (selected == 1) {
|
||||||
|
config.position.position_broadcast_secs = 60;
|
||||||
|
} else if (selected == 2) {
|
||||||
|
config.position.position_broadcast_secs = 90;
|
||||||
|
} else if (selected == 3) {
|
||||||
|
config.position.position_broadcast_secs = 300;
|
||||||
|
} else if (selected == 4) {
|
||||||
|
config.position.position_broadcast_secs = 900;
|
||||||
|
} else if (selected == 5) {
|
||||||
|
config.position.position_broadcast_secs = 3600;
|
||||||
|
} else if (selected == 6) {
|
||||||
|
config.position.position_broadcast_secs = 7200;
|
||||||
|
} else if (selected == 7) {
|
||||||
|
config.position.position_broadcast_secs = 10800;
|
||||||
|
} else if (selected == 8) {
|
||||||
|
config.position.position_broadcast_secs = 14400;
|
||||||
|
} else if (selected == 9) {
|
||||||
|
config.position.position_broadcast_secs = 18000;
|
||||||
|
} else if (selected == 10) {
|
||||||
|
config.position.position_broadcast_secs = 21600;
|
||||||
|
} else if (selected == 11) {
|
||||||
|
config.position.position_broadcast_secs = 43200;
|
||||||
|
} else if (selected == 12) {
|
||||||
|
config.position.position_broadcast_secs = 64800;
|
||||||
|
} else if (selected == 13) {
|
||||||
|
config.position.position_broadcast_secs = 86400;
|
||||||
|
} else if (selected == 14) {
|
||||||
|
config.position.position_broadcast_secs = 129600;
|
||||||
|
} else if (selected == 15) {
|
||||||
|
config.position.position_broadcast_secs = 172800;
|
||||||
|
} else if (selected == 16) {
|
||||||
|
config.position.position_broadcast_secs = 259200;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected != 0) {
|
||||||
|
saveUIConfig();
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.position.position_broadcast_secs == 60) {
|
||||||
|
bannerOptions.InitialSelected = 1;
|
||||||
|
} else if (config.position.position_broadcast_secs == 90) {
|
||||||
|
bannerOptions.InitialSelected = 2;
|
||||||
|
} else if (config.position.position_broadcast_secs == 300) {
|
||||||
|
bannerOptions.InitialSelected = 3;
|
||||||
|
} else if (config.position.position_broadcast_secs == 900) {
|
||||||
|
bannerOptions.InitialSelected = 4;
|
||||||
|
} else if (config.position.position_broadcast_secs == 3600) {
|
||||||
|
bannerOptions.InitialSelected = 5;
|
||||||
|
} else if (config.position.position_broadcast_secs == 7200) {
|
||||||
|
bannerOptions.InitialSelected = 6;
|
||||||
|
} else if (config.position.position_broadcast_secs == 10800) {
|
||||||
|
bannerOptions.InitialSelected = 7;
|
||||||
|
} else if (config.position.position_broadcast_secs == 14400) {
|
||||||
|
bannerOptions.InitialSelected = 8;
|
||||||
|
} else if (config.position.position_broadcast_secs == 18000) {
|
||||||
|
bannerOptions.InitialSelected = 9;
|
||||||
|
} else if (config.position.position_broadcast_secs == 21600) {
|
||||||
|
bannerOptions.InitialSelected = 10;
|
||||||
|
} else if (config.position.position_broadcast_secs == 43200) {
|
||||||
|
bannerOptions.InitialSelected = 11;
|
||||||
|
} else if (config.position.position_broadcast_secs == 64800) {
|
||||||
|
bannerOptions.InitialSelected = 12;
|
||||||
|
} else if (config.position.position_broadcast_secs == 86400) {
|
||||||
|
bannerOptions.InitialSelected = 13;
|
||||||
|
} else if (config.position.position_broadcast_secs == 129600) {
|
||||||
|
bannerOptions.InitialSelected = 14;
|
||||||
|
} else if (config.position.position_broadcast_secs == 172800) {
|
||||||
|
bannerOptions.InitialSelected = 15;
|
||||||
|
} else if (config.position.position_broadcast_secs == 259200) {
|
||||||
|
bannerOptions.InitialSelected = 16;
|
||||||
|
} else {
|
||||||
|
bannerOptions.InitialSelected = 0;
|
||||||
|
}
|
||||||
|
screen->showOverlayBanner(bannerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void menuHandler::BluetoothToggleMenu()
|
void menuHandler::BluetoothToggleMenu()
|
||||||
@@ -1372,9 +1620,9 @@ void menuHandler::BluetoothToggleMenu()
|
|||||||
|
|
||||||
void menuHandler::BuzzerModeMenu()
|
void menuHandler::BuzzerModeMenu()
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only", "DMs Only"};
|
static const char *optionsArray[] = {"All Enabled", "All Disabled", "Notifications", "System Only", "DMs Only"};
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Buzzer Mode";
|
bannerOptions.message = "Notification Sounds";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 5;
|
bannerOptions.optionsCount = 5;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
@@ -1749,30 +1997,6 @@ void menuHandler::wifiToggleMenu()
|
|||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler::notificationsMenu()
|
|
||||||
{
|
|
||||||
enum optionsNumbers { Back, BuzzerActions };
|
|
||||||
static const char *optionsArray[] = {"Back", "Buzzer Actions"};
|
|
||||||
static int optionsEnumArray[] = {Back, BuzzerActions};
|
|
||||||
int options = 2;
|
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
|
||||||
bannerOptions.message = "Notifications";
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
|
||||||
bannerOptions.optionsCount = options;
|
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
|
||||||
if (selected == BuzzerActions) {
|
|
||||||
menuHandler::menuQueue = menuHandler::buzzermodemenupicker;
|
|
||||||
screen->runNow();
|
|
||||||
} else {
|
|
||||||
menuQueue = system_base_menu;
|
|
||||||
screen->runNow();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
screen->showOverlayBanner(bannerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void menuHandler::screenOptionsMenu()
|
void menuHandler::screenOptionsMenu()
|
||||||
{
|
{
|
||||||
// Check if brightness is supported
|
// Check if brightness is supported
|
||||||
@@ -2126,6 +2350,15 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
case gps_format_menu:
|
case gps_format_menu:
|
||||||
GPSFormatMenu();
|
GPSFormatMenu();
|
||||||
break;
|
break;
|
||||||
|
case gps_smart_position_menu:
|
||||||
|
GPSSmartPositionMenu();
|
||||||
|
break;
|
||||||
|
case gps_update_interval_menu:
|
||||||
|
GPSUpdateIntervalMenu();
|
||||||
|
break;
|
||||||
|
case gps_position_broadcast_menu:
|
||||||
|
GPSPositionBroadcastMenu();
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case compass_point_north_menu:
|
case compass_point_north_menu:
|
||||||
compassNorthMenu();
|
compassNorthMenu();
|
||||||
@@ -2181,9 +2414,6 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
case bluetooth_toggle_menu:
|
case bluetooth_toggle_menu:
|
||||||
BluetoothToggleMenu();
|
BluetoothToggleMenu();
|
||||||
break;
|
break;
|
||||||
case notifications_menu:
|
|
||||||
notificationsMenu();
|
|
||||||
break;
|
|
||||||
case screen_options_menu:
|
case screen_options_menu:
|
||||||
screenOptionsMenu();
|
screenOptionsMenu();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ class menuHandler
|
|||||||
node_base_menu,
|
node_base_menu,
|
||||||
gps_toggle_menu,
|
gps_toggle_menu,
|
||||||
gps_format_menu,
|
gps_format_menu,
|
||||||
|
gps_smart_position_menu,
|
||||||
|
gps_update_interval_menu,
|
||||||
|
gps_position_broadcast_menu,
|
||||||
compass_point_north_menu,
|
compass_point_north_menu,
|
||||||
reset_node_db_menu,
|
reset_node_db_menu,
|
||||||
buzzermodemenupicker,
|
buzzermodemenupicker,
|
||||||
@@ -36,7 +39,6 @@ class menuHandler
|
|||||||
number_test,
|
number_test,
|
||||||
wifi_toggle_menu,
|
wifi_toggle_menu,
|
||||||
bluetooth_toggle_menu,
|
bluetooth_toggle_menu,
|
||||||
notifications_menu,
|
|
||||||
screen_options_menu,
|
screen_options_menu,
|
||||||
power_menu,
|
power_menu,
|
||||||
system_base_menu,
|
system_base_menu,
|
||||||
@@ -77,6 +79,9 @@ class menuHandler
|
|||||||
static void compassNorthMenu();
|
static void compassNorthMenu();
|
||||||
static void GPSToggleMenu();
|
static void GPSToggleMenu();
|
||||||
static void GPSFormatMenu();
|
static void GPSFormatMenu();
|
||||||
|
static void GPSSmartPositionMenu();
|
||||||
|
static void GPSUpdateIntervalMenu();
|
||||||
|
static void GPSPositionBroadcastMenu();
|
||||||
static void BuzzerModeMenu();
|
static void BuzzerModeMenu();
|
||||||
static void switchToMUIMenu();
|
static void switchToMUIMenu();
|
||||||
static void TFTColorPickerMenu(OLEDDisplay *display);
|
static void TFTColorPickerMenu(OLEDDisplay *display);
|
||||||
@@ -92,7 +97,6 @@ class menuHandler
|
|||||||
static void numberTest();
|
static void numberTest();
|
||||||
static void wifiBaseMenu();
|
static void wifiBaseMenu();
|
||||||
static void wifiToggleMenu();
|
static void wifiToggleMenu();
|
||||||
static void notificationsMenu();
|
|
||||||
static void screenOptionsMenu();
|
static void screenOptionsMenu();
|
||||||
static void powerMenu();
|
static void powerMenu();
|
||||||
static void nodeNameLengthMenu();
|
static void nodeNameLengthMenu();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
||||||
|
|
||||||
#include "./PositionsApplet.h"
|
#include "./PositionsApplet.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
|
||||||
using namespace NicheGraphics;
|
using namespace NicheGraphics;
|
||||||
|
|
||||||
@@ -49,8 +50,8 @@ ProcessMessage InkHUD::PositionsApplet::handleReceived(const meshtastic_MeshPack
|
|||||||
if (!hasPosition)
|
if (!hasPosition)
|
||||||
return ProcessMessage::CONTINUE;
|
return ProcessMessage::CONTINUE;
|
||||||
|
|
||||||
bool hasHopsAway = (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start); // From NodeDB::updateFrom
|
const int8_t hopsAway = getHopsAway(mp);
|
||||||
uint8_t hopsAway = mp.hop_start - mp.hop_limit;
|
const bool hasHopsAway = hopsAway >= 0;
|
||||||
|
|
||||||
// Determine if the position packet would change anything on-screen
|
// Determine if the position packet would change anything on-screen
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ bool RotaryEncoderInterruptImpl1::init()
|
|||||||
RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
|
RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
|
||||||
RotaryEncoderInterruptImpl1::handleIntPressed);
|
RotaryEncoderInterruptImpl1::handleIntPressed);
|
||||||
inputBroker->registerSource(this);
|
inputBroker->registerSource(this);
|
||||||
|
#ifndef HAS_PHYSICAL_KEYBOARD
|
||||||
osk_found = true;
|
osk_found = true;
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLef
|
|||||||
|
|
||||||
LOG_DEBUG("Trackball GPIO initialized - UP:%d DOWN:%d LEFT:%d RIGHT:%d PRESS:%d", this->_pinUp, this->_pinDown,
|
LOG_DEBUG("Trackball GPIO initialized - UP:%d DOWN:%d LEFT:%d RIGHT:%d PRESS:%d", this->_pinUp, this->_pinDown,
|
||||||
this->_pinLeft, this->_pinRight, pinPress);
|
this->_pinLeft, this->_pinRight, pinPress);
|
||||||
|
#ifndef HAS_PHYSICAL_KEYBOARD
|
||||||
osk_found = true;
|
osk_found = true;
|
||||||
|
#endif
|
||||||
this->setInterval(100);
|
this->setInterval(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ bool UpDownInterruptImpl1::init()
|
|||||||
eventDownLong, UpDownInterruptImpl1::handleIntDown, UpDownInterruptImpl1::handleIntUp,
|
eventDownLong, UpDownInterruptImpl1::handleIntDown, UpDownInterruptImpl1::handleIntUp,
|
||||||
UpDownInterruptImpl1::handleIntPressed);
|
UpDownInterruptImpl1::handleIntPressed);
|
||||||
inputBroker->registerSource(this);
|
inputBroker->registerSource(this);
|
||||||
|
#ifndef HAS_PHYSICAL_KEYBOARD
|
||||||
osk_found = true;
|
osk_found = true;
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1186,11 +1186,6 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PIN_PWR_DELAY_MS
|
|
||||||
// This may be required to give the peripherals time to power up.
|
|
||||||
delay(PIN_PWR_DELAY_MS);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
// as one can't use a function pointer to the class constructor:
|
// as one can't use a function pointer to the class constructor:
|
||||||
auto loraModuleInterface = [](LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
|
auto loraModuleInterface = [](LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
|
||||||
@@ -1465,8 +1460,10 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAS_TRACKBALL) || (defined(INPUTDRIVER_ENCODER_TYPE) && INPUTDRIVER_ENCODER_TYPE == 2)
|
#if defined(HAS_TRACKBALL) || (defined(INPUTDRIVER_ENCODER_TYPE) && INPUTDRIVER_ENCODER_TYPE == 2)
|
||||||
|
#ifndef HAS_PHYSICAL_KEYBOARD
|
||||||
osk_found = true;
|
osk_found = true;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER
|
||||||
// Start web server thread.
|
// Start web server thread.
|
||||||
|
|||||||
@@ -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.hop_start, mp.hop_limit));
|
routingModule->getHopLimitForResponse(mp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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.hop_start, to.hop_limit);
|
p->hop_limit = routingModule->getHopLimitForResponse(to);
|
||||||
|
|
||||||
// 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,11 +95,8 @@ 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)) {
|
||||||
// Hops used by the request. If somebody in between running modified firmware modified it, ignore it
|
const int8_t hopsUsed = getHopsAway(*mp, config.lora.hop_limit);
|
||||||
auto hopStart = mp->hop_start;
|
if (hopsUsed > (int32_t)(config.lora.hop_limit + 2)) {
|
||||||
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);
|
||||||
@@ -195,15 +192,13 @@ 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 HAS_SCREEN
|
IF_SCREEN(if (p.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && p.decoded.payload.size > 0 &&
|
||||||
if (p.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && p.decoded.payload.size > 0 && p.to != NODENUM_BROADCAST &&
|
p.to != NODENUM_BROADCAST && p.to != 0) // DM only
|
||||||
p.to != 0) // DM only
|
{
|
||||||
{
|
perhapsDecode(&p);
|
||||||
perhapsDecode(&p);
|
const StoredMessage &sm = messageStore.addFromPacket(p);
|
||||||
const StoredMessage &sm = messageStore.addFromPacket(p);
|
graphics::MessageRenderer::handleNewMessage(nullptr, sm, p); // notify UI
|
||||||
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 = p->hop_start > 0 && p->hop_start == p->hop_limit;
|
bool isRepeated = getHopsAway(*p) == 0;
|
||||||
// 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,8 +101,7 @@ 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) ||
|
if ((weWereRelayer && wasAlreadyRelayer) || (getHopsAway(*p) == 0 && weWereSoleRelayer)) {
|
||||||
(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);
|
||||||
|
|||||||
@@ -805,7 +805,8 @@ void NodeDB::installDefaultModuleConfig()
|
|||||||
moduleConfig.external_notification.output_ms = 500;
|
moduleConfig.external_notification.output_ms = 500;
|
||||||
moduleConfig.external_notification.nag_timeout = 2;
|
moduleConfig.external_notification.nag_timeout = 2;
|
||||||
#endif
|
#endif
|
||||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3)
|
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3) || \
|
||||||
|
defined(ELECROW_ThinkNode_M6)
|
||||||
// Default to PIN_LED2 for external notification output (LED color depends on device variant)
|
// Default to PIN_LED2 for external notification output (LED color depends on device variant)
|
||||||
moduleConfig.external_notification.enabled = true;
|
moduleConfig.external_notification.enabled = true;
|
||||||
moduleConfig.external_notification.output = PIN_LED2;
|
moduleConfig.external_notification.output = PIN_LED2;
|
||||||
@@ -1548,6 +1549,23 @@ 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)
|
||||||
@@ -1800,9 +1818,10 @@ 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
|
||||||
if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) {
|
const int8_t hopsAway = getHopsAway(mp);
|
||||||
|
if (hopsAway >= 0) {
|
||||||
info->has_hops_away = true;
|
info->has_hops_away = true;
|
||||||
info->hops_away = mp.hop_start - mp.hop_limit;
|
info->hops_away = hopsAway;
|
||||||
}
|
}
|
||||||
sortMeshDB();
|
sortMeshDB();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ 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,
|
||||||
|
|||||||
@@ -171,7 +171,8 @@ const RegionInfo regions[] = {
|
|||||||
863 - 868 MHz <25 mW EIRP, 500kHz channels allowed, must not be used at airfields
|
863 - 868 MHz <25 mW EIRP, 500kHz channels allowed, must not be used at airfields
|
||||||
https://github.com/meshtastic/firmware/issues/7204
|
https://github.com/meshtastic/firmware/issues/7204
|
||||||
*/
|
*/
|
||||||
RDEF(KZ_433, 433.075f, 434.775f, 100, 0, 10, true, false, false), RDEF(KZ_863, 863.0f, 868.0f, 100, 0, 30, true, false, true),
|
RDEF(KZ_433, 433.075f, 434.775f, 100, 0, 10, true, false, false),
|
||||||
|
RDEF(KZ_863, 863.0f, 868.0f, 100, 0, 30, true, false, false),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Nepal
|
Nepal
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#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"
|
||||||
@@ -108,12 +109,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->hop_start, p->hop_limit), true);
|
routingModule->getHopLimitForResponse(*p), 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->hop_start, p->hop_limit));
|
routingModule->getHopLimitForResponse(*p));
|
||||||
} else if ((p->hop_start > 0 && p->hop_start == p->hop_limit) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
|
} else if ((getHopsAway(*p) == 0) || 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.
|
||||||
@@ -123,11 +124,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->hop_start, p->hop_limit));
|
routingModule->getHopLimitForResponse(*p));
|
||||||
} 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->hop_start, p->hop_limit));
|
routingModule->getHopLimitForResponse(*p));
|
||||||
}
|
}
|
||||||
} 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,8 +81,7 @@ 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
|
||||||
bool isFirstHop = (p->hop_start != 0 && p->hop_start == p->hop_limit);
|
if (getHopsAway(*p) == 0) {
|
||||||
if (isFirstHop) {
|
|
||||||
return true; // Always decrement on first hop
|
return true; // Always decrement on first hop
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,7 +729,8 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
|||||||
meshtastic_PortNum_POSITION_APP, meshtastic_PortNum_NODEINFO_APP, meshtastic_PortNum_ROUTING_APP,
|
meshtastic_PortNum_POSITION_APP, meshtastic_PortNum_NODEINFO_APP, meshtastic_PortNum_ROUTING_APP,
|
||||||
meshtastic_PortNum_TELEMETRY_APP, meshtastic_PortNum_ADMIN_APP, meshtastic_PortNum_ALERT_APP,
|
meshtastic_PortNum_TELEMETRY_APP, meshtastic_PortNum_ADMIN_APP, meshtastic_PortNum_ALERT_APP,
|
||||||
meshtastic_PortNum_KEY_VERIFICATION_APP, meshtastic_PortNum_WAYPOINT_APP,
|
meshtastic_PortNum_KEY_VERIFICATION_APP, meshtastic_PortNum_WAYPOINT_APP,
|
||||||
meshtastic_PortNum_STORE_FORWARD_APP, meshtastic_PortNum_TRACEROUTE_APP)) {
|
meshtastic_PortNum_STORE_FORWARD_APP, meshtastic_PortNum_TRACEROUTE_APP,
|
||||||
|
meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP)) {
|
||||||
LOG_DEBUG("Ignore packet on non-standard portnum for CORE_PORTNUMS_ONLY");
|
LOG_DEBUG("Ignore packet on non-standard portnum for CORE_PORTNUMS_ONLY");
|
||||||
cancelSending(p->from, p->id);
|
cancelSending(p->from, p->id);
|
||||||
skipHandle = true;
|
skipHandle = true;
|
||||||
@@ -745,15 +745,19 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
|||||||
MeshModule::callModules(*p, src);
|
MeshModule::callModules(*p, src);
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||||
// Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not to
|
if (p_encrypted == nullptr) {
|
||||||
// us (because we would be able to decrypt it)
|
LOG_WARN("p_encrypted is null, skipping MQTT publish");
|
||||||
if (decodedState == DecodeState::DECODE_FAILURE && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 &&
|
} else {
|
||||||
!isBroadcast(p->to) && !isToUs(p))
|
// Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not
|
||||||
p_encrypted->pki_encrypted = true;
|
// to us (because we would be able to decrypt it)
|
||||||
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
|
if (decodedState == DecodeState::DECODE_FAILURE && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 &&
|
||||||
if ((decodedState == DecodeState::DECODE_SUCCESS || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled &&
|
!isBroadcast(p->to) && !isToUs(p))
|
||||||
!isFromUs(p) && mqtt)
|
p_encrypted->pki_encrypted = true;
|
||||||
mqtt->onSend(*p_encrypted, *p, p->channel);
|
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
|
||||||
|
if ((decodedState == DecodeState::DECODE_SUCCESS || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled &&
|
||||||
|
!isFromUs(p) && mqtt)
|
||||||
|
mqtt->onSend(*p_encrypted, *p, p->channel);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -822,6 +822,8 @@ 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 */
|
||||||
@@ -1428,7 +1430,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}
|
#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_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}
|
||||||
@@ -1460,7 +1462,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}
|
#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_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}
|
||||||
@@ -1548,6 +1550,7 @@ 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
|
||||||
@@ -1773,7 +1776,8 @@ 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
|
||||||
|
|
||||||
@@ -2143,7 +2147,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 371
|
#define meshtastic_StoreForwardPlusPlus_size 377
|
||||||
#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
|
||||||
|
|||||||
@@ -115,7 +115,6 @@ namespace graphics
|
|||||||
extern int bannerSignalBars;
|
extern int bannerSignalBars;
|
||||||
}
|
}
|
||||||
extern ScanI2C::DeviceAddress cardkb_found;
|
extern ScanI2C::DeviceAddress cardkb_found;
|
||||||
extern bool graphics::isMuted;
|
|
||||||
extern bool osk_found;
|
extern bool osk_found;
|
||||||
|
|
||||||
static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto";
|
static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto";
|
||||||
|
|||||||
@@ -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 (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
|
} else if (getHopsAway(mp) == 0) {
|
||||||
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,
|
||||||
|
|||||||
@@ -429,7 +429,9 @@ int32_t PositionModule::runOnce()
|
|||||||
|
|
||||||
if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
|
if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
|
||||||
if (waitingForFreshPosition) {
|
if (waitingForFreshPosition) {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG("Skip initial position send; no fresh position since boot");
|
LOG_DEBUG("Skip initial position send; no fresh position since boot");
|
||||||
|
#endif
|
||||||
} else if (nodeDB->hasValidPosition(node)) {
|
} else if (nodeDB->hasValidPosition(node)) {
|
||||||
lastGpsSend = now;
|
lastGpsSend = now;
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
|
|||||||
// In event mode we want to prevent excessive position broadcasts
|
// In event mode we want to prevent excessive position broadcasts
|
||||||
// we set the minimum interval to 5m
|
// we set the minimum interval to 5m
|
||||||
const uint32_t minimumTimeThreshold =
|
const uint32_t minimumTimeThreshold =
|
||||||
max(300000, Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30));
|
max(uint32_t(300000), Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30));
|
||||||
#else
|
#else
|
||||||
const uint32_t minimumTimeThreshold =
|
const uint32_t minimumTimeThreshold =
|
||||||
Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
|
Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
|
||||||
|
|||||||
@@ -58,12 +58,11 @@ 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(uint8_t hopStart, uint8_t hopLimit)
|
uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp)
|
||||||
{
|
{
|
||||||
if (hopStart != 0) {
|
const int8_t hopsUsed = getHopsAway(mp);
|
||||||
// Hops used by the request. If somebody in between running modified firmware modified it, ignore it
|
if (hopsUsed >= 0) {
|
||||||
uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
|
if (hopsUsed > (int32_t)(config.lora.hop_limit)) {
|
||||||
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(uint8_t hopStart, uint8_t hopLimit);
|
uint8_t getHopLimitForResponse(const meshtastic_MeshPacket &mp);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Router;
|
friend class Router;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
|||||||
switch (arg->getStatusType()) {
|
switch (arg->getStatusType()) {
|
||||||
case STATUS_TYPE_POWER: {
|
case STATUS_TYPE_POWER: {
|
||||||
meshtastic::PowerStatus *powerStatus = (meshtastic::PowerStatus *)arg;
|
meshtastic::PowerStatus *powerStatus = (meshtastic::PowerStatus *)arg;
|
||||||
if (powerStatus->getHasUSB()) {
|
if (powerStatus->getHasUSB() || powerStatus->getIsCharging()) {
|
||||||
power_state = charging;
|
power_state = charging;
|
||||||
if (powerStatus->getBatteryChargePercent() >= 100) {
|
if (powerStatus->getBatteryChargePercent() >= 100) {
|
||||||
power_state = charged;
|
power_state = charged;
|
||||||
|
|||||||
@@ -45,10 +45,9 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
|
|||||||
// Mute
|
// Mute
|
||||||
case INPUT_BROKER_MSG_MUTE_TOGGLE:
|
case INPUT_BROKER_MSG_MUTE_TOGGLE:
|
||||||
if (moduleConfig.external_notification.enabled && externalNotificationModule) {
|
if (moduleConfig.external_notification.enabled && externalNotificationModule) {
|
||||||
bool isMuted = externalNotificationModule->getMute();
|
externalNotificationModule->setMute(externalNotificationModule->getMute());
|
||||||
externalNotificationModule->setMute(!isMuted);
|
IF_SCREEN(if (!externalNotificationModule->getMute()) externalNotificationModule->stopNow(); screen->showSimpleBanner(
|
||||||
IF_SCREEN(graphics::isMuted = !isMuted; if (!isMuted) externalNotificationModule->stopNow();
|
externalNotificationModule->getMute() ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);)
|
||||||
screen->showSimpleBanner(isMuted ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);)
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
// Bluetooth
|
// Bluetooth
|
||||||
|
|||||||
@@ -21,18 +21,17 @@ 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 HAS_SCREEN
|
IF_SCREEN(
|
||||||
// Guard against running in MeshtasticUI
|
// Guard against running in MeshtasticUI or with no screen
|
||||||
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,5 +1,6 @@
|
|||||||
#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"
|
||||||
@@ -359,10 +360,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
|
||||||
if (p.hop_start != 0 && p.hop_limit <= p.hop_start) {
|
const int8_t hopsTaken = getHopsAway(p);
|
||||||
uint8_t hopsTaken = p.hop_start - p.hop_limit;
|
if (hopsTaken >= 0) {
|
||||||
int8_t diff = hopsTaken - *route_count;
|
int8_t diff = hopsTaken - *route_count;
|
||||||
for (uint8_t i = 0; i < diff; i++) {
|
for (int8_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;
|
||||||
@@ -370,7 +371,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 (uint8_t i = 0; i < diff; i++) {
|
for (int8_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;
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
#include "NimBLEAdvertising.h"
|
#include "NimBLEAdvertising.h"
|
||||||
#ifdef CONFIG_BT_NIMBLE_EXT_ADV
|
|
||||||
#include "NimBLEExtAdvertising.h"
|
#include "NimBLEExtAdvertising.h"
|
||||||
#endif
|
|
||||||
#include "PowerStatus.h"
|
#include "PowerStatus.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||||
#include "host/ble_gap.h"
|
#include "host/ble_gap.h"
|
||||||
@@ -26,12 +26,15 @@
|
|||||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr uint16_t kPreferredBleMtu = 517;
|
constexpr uint16_t kPreferredBleMtu = 517;
|
||||||
constexpr uint16_t kPreferredBleTxOctets = 251;
|
constexpr uint16_t kPreferredBleTxOctets = 251;
|
||||||
constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8;
|
constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
// Debugging options: careful, they slow things down quite a bit!
|
// Debugging options: careful, they slow things down quite a bit!
|
||||||
// #define DEBUG_NIMBLE_ON_READ_TIMING // uncomment to time onRead duration
|
// #define DEBUG_NIMBLE_ON_READ_TIMING // uncomment to time onRead duration
|
||||||
@@ -310,9 +313,11 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
|||||||
{
|
{
|
||||||
PhoneAPI::onNowHasData(fromRadioNum);
|
PhoneAPI::onNowHasData(fromRadioNum);
|
||||||
|
|
||||||
#ifdef DEBUG_NIMBLE_NOTIFY
|
|
||||||
int currentNotifyCount = notifyCount.fetch_add(1);
|
int currentNotifyCount = notifyCount.fetch_add(1);
|
||||||
|
|
||||||
uint8_t cc = bleServer->getConnectedCount();
|
uint8_t cc = bleServer->getConnectedCount();
|
||||||
|
|
||||||
|
#ifdef DEBUG_NIMBLE_NOTIFY
|
||||||
// This logging slows things down when there are lots of packets going to the phone, like initial connection:
|
// This logging slows things down when there are lots of packets going to the phone, like initial connection:
|
||||||
LOG_DEBUG("BLE notify(%d) fromNum: %d connections: %d", currentNotifyCount, fromRadioNum, cc);
|
LOG_DEBUG("BLE notify(%d) fromNum: %d connections: %d", currentNotifyCount, fromRadioNum, cc);
|
||||||
#endif
|
#endif
|
||||||
@@ -321,7 +326,13 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
|||||||
put_le32(val, fromRadioNum);
|
put_le32(val, fromRadioNum);
|
||||||
|
|
||||||
fromNumCharacteristic->setValue(val, sizeof(val));
|
fromNumCharacteristic->setValue(val, sizeof(val));
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
|
// NOTE: I don't have any NIMBLE_TWO devices, but this line makes me suspicious, and I suspect it needs to just be
|
||||||
|
// notify().
|
||||||
fromNumCharacteristic->notify(val, sizeof(val), BLE_HS_CONN_HANDLE_NONE);
|
fromNumCharacteristic->notify(val, sizeof(val), BLE_HS_CONN_HANDLE_NONE);
|
||||||
|
#else
|
||||||
|
fromNumCharacteristic->notify();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the current underlying physical link to see if the client is currently connected
|
/// Check the current underlying physical link to see if the client is currently connected
|
||||||
@@ -386,7 +397,12 @@ static uint8_t lastToRadio[MAX_TO_FROM_RADIO_SIZE];
|
|||||||
|
|
||||||
class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
||||||
{
|
{
|
||||||
void onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onWrite(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo)
|
||||||
|
#else
|
||||||
|
virtual void onWrite(NimBLECharacteristic *pCharacteristic)
|
||||||
|
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
||||||
// Assumption: onWrite is serialized by NimBLE, so we don't need to lock here against multiple concurrent onWrite calls.
|
// Assumption: onWrite is serialized by NimBLE, so we don't need to lock here against multiple concurrent onWrite calls.
|
||||||
@@ -433,7 +449,11 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
|||||||
|
|
||||||
class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
||||||
{
|
{
|
||||||
void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo)
|
||||||
|
#else
|
||||||
|
virtual void onRead(NimBLECharacteristic *pCharacteristic)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
// CAUTION: This callback runs in the NimBLE task!!! Don't do anything except communicate with the main task's runOnce.
|
||||||
|
|
||||||
@@ -541,27 +561,32 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
|||||||
|
|
||||||
class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
||||||
{
|
{
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
public:
|
public:
|
||||||
explicit NimbleBluetoothServerCallback(NimbleBluetooth *ble) : ble(ble) {}
|
NimbleBluetoothServerCallback(NimbleBluetooth *ble) { this->ble = ble; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NimbleBluetooth *ble;
|
NimbleBluetooth *ble;
|
||||||
|
|
||||||
uint32_t onPassKeyDisplay() override
|
virtual uint32_t onPassKeyDisplay()
|
||||||
|
#else
|
||||||
|
virtual uint32_t onPassKeyRequest()
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
uint32_t passkey = config.bluetooth.fixed_pin;
|
uint32_t passkey = config.bluetooth.fixed_pin;
|
||||||
|
|
||||||
if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN) {
|
if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN) {
|
||||||
LOG_INFO("Use random passkey");
|
LOG_INFO("Use random passkey");
|
||||||
|
// This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
|
||||||
passkey = random(100000, 999999);
|
passkey = random(100000, 999999);
|
||||||
}
|
}
|
||||||
LOG_INFO("*** Enter passkey %06u on the peer side ***", passkey);
|
LOG_INFO("*** Enter passkey %d on the peer side ***", passkey);
|
||||||
|
|
||||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||||
meshtastic::BluetoothStatus newStatus(std::to_string(passkey));
|
meshtastic::BluetoothStatus newStatus(std::to_string(passkey));
|
||||||
bluetoothStatus->updateStatus(&newStatus);
|
bluetoothStatus->updateStatus(&newStatus);
|
||||||
|
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN // Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||||
if (screen) {
|
if (screen) {
|
||||||
screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||||
char btPIN[16] = "888888";
|
char btPIN[16] = "888888";
|
||||||
@@ -590,29 +615,39 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
passkeyShowing = true;
|
passkeyShowing = true;
|
||||||
|
|
||||||
return passkey;
|
return passkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAuthenticationComplete(NimBLEConnInfo &connInfo) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onAuthenticationComplete(NimBLEConnInfo &connInfo)
|
||||||
|
#else
|
||||||
|
virtual void onAuthenticationComplete(ble_gap_conn_desc *desc)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
LOG_INFO("BLE authentication complete");
|
LOG_INFO("BLE authentication complete");
|
||||||
|
|
||||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
||||||
bluetoothStatus->updateStatus(&newStatus);
|
bluetoothStatus->updateStatus(&newStatus);
|
||||||
|
|
||||||
|
// Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||||
if (passkeyShowing) {
|
if (passkeyShowing) {
|
||||||
passkeyShowing = false;
|
passkeyShowing = false;
|
||||||
if (screen) {
|
if (screen)
|
||||||
screen->endAlert();
|
screen->endAlert();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the connection handle for future use
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
nimbleBluetoothConnHandle = connInfo.getConnHandle();
|
nimbleBluetoothConnHandle = connInfo.getConnHandle();
|
||||||
|
#else
|
||||||
|
nimbleBluetoothConnHandle = desc->conn_handle;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo)
|
||||||
{
|
{
|
||||||
LOG_INFO("BLE incoming connection %s", connInfo.getAddress().toString().c_str());
|
LOG_INFO("BLE incoming connection %s", connInfo.getAddress().toString().c_str());
|
||||||
|
|
||||||
@@ -637,12 +672,21 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
LOG_INFO("BLE conn %u initial MTU %u (target %u)", connHandle, connInfo.getMTU(), kPreferredBleMtu);
|
LOG_INFO("BLE conn %u initial MTU %u (target %u)", connHandle, connInfo.getMTU(), kPreferredBleMtu);
|
||||||
pServer->updateConnParams(connHandle, 6, 12, 0, 200);
|
pServer->updateConnParams(connHandle, 6, 12, 0, 200);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason) override
|
#ifdef NIMBLE_TWO
|
||||||
|
virtual void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason)
|
||||||
{
|
{
|
||||||
LOG_INFO("BLE disconnect reason: %d", reason);
|
LOG_INFO("BLE disconnect reason: %d", reason);
|
||||||
|
#else
|
||||||
|
virtual void onDisconnect(NimBLEServer *pServer, ble_gap_conn_desc *desc)
|
||||||
|
{
|
||||||
|
LOG_INFO("BLE disconnect");
|
||||||
|
#endif
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
if (ble->isDeInit)
|
if (ble->isDeInit)
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
||||||
bluetoothStatus->updateStatus(&newStatus);
|
bluetoothStatus->updateStatus(&newStatus);
|
||||||
@@ -666,69 +710,35 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
bluetoothPhoneAPI->writeCount = 0;
|
bluetoothPhoneAPI->writeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection
|
||||||
memset(lastToRadio, 0, sizeof(lastToRadio));
|
memset(lastToRadio, 0, sizeof(lastToRadio));
|
||||||
|
|
||||||
nimbleBluetoothConnHandle = BLE_HS_CONN_HANDLE_NONE;
|
nimbleBluetoothConnHandle = BLE_HS_CONN_HANDLE_NONE; // BLE_HS_CONN_HANDLE_NONE means "no connection"
|
||||||
|
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
|
// Restart Advertising
|
||||||
ble->startAdvertising();
|
ble->startAdvertising();
|
||||||
|
#else
|
||||||
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
if (!pAdvertising->start(0)) {
|
||||||
|
if (pAdvertising->isAdvertising()) {
|
||||||
|
LOG_DEBUG("BLE advertising already running");
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("BLE failed to restart advertising");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
|
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
|
||||||
static NimbleBluetoothFromRadioCallback *fromRadioCallbacks;
|
static NimbleBluetoothFromRadioCallback *fromRadioCallbacks;
|
||||||
|
|
||||||
void NimbleBluetooth::startAdvertising()
|
|
||||||
{
|
|
||||||
#if defined(CONFIG_BT_NIMBLE_EXT_ADV)
|
|
||||||
NimBLEExtAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
|
||||||
NimBLEExtAdvertisement legacyAdvertising;
|
|
||||||
|
|
||||||
legacyAdvertising.setLegacyAdvertising(true);
|
|
||||||
legacyAdvertising.setScannable(true);
|
|
||||||
legacyAdvertising.setConnectable(true);
|
|
||||||
legacyAdvertising.setFlags(BLE_HS_ADV_F_DISC_GEN);
|
|
||||||
if (powerStatus->getHasBattery() == 1) {
|
|
||||||
legacyAdvertising.setCompleteServices(NimBLEUUID((uint16_t)0x180f));
|
|
||||||
}
|
|
||||||
legacyAdvertising.setCompleteServices(NimBLEUUID(MESH_SERVICE_UUID));
|
|
||||||
legacyAdvertising.setMinInterval(500);
|
|
||||||
legacyAdvertising.setMaxInterval(1000);
|
|
||||||
|
|
||||||
NimBLEExtAdvertisement legacyScanResponse;
|
|
||||||
legacyScanResponse.setLegacyAdvertising(true);
|
|
||||||
legacyScanResponse.setConnectable(true);
|
|
||||||
legacyScanResponse.setName(getDeviceName());
|
|
||||||
|
|
||||||
if (!pAdvertising->setInstanceData(0, legacyAdvertising)) {
|
|
||||||
LOG_ERROR("BLE failed to set legacyAdvertising");
|
|
||||||
} else if (!pAdvertising->setScanResponseData(0, legacyScanResponse)) {
|
|
||||||
LOG_ERROR("BLE failed to set legacyScanResponse");
|
|
||||||
} else if (!pAdvertising->start(0, 0, 0)) {
|
|
||||||
LOG_ERROR("BLE failed to start legacyAdvertising");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
|
||||||
pAdvertising->reset();
|
|
||||||
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
|
|
||||||
if (powerStatus->getHasBattery() == 1) {
|
|
||||||
pAdvertising->addServiceUUID(NimBLEUUID((uint16_t)0x180f));
|
|
||||||
}
|
|
||||||
|
|
||||||
NimBLEAdvertisementData scan;
|
|
||||||
scan.setName(getDeviceName());
|
|
||||||
pAdvertising->setScanResponseData(scan);
|
|
||||||
pAdvertising->enableScanResponse(true);
|
|
||||||
|
|
||||||
if (!pAdvertising->start(0)) {
|
|
||||||
LOG_ERROR("BLE failed to start advertising");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
LOG_DEBUG("BLE Advertising started");
|
|
||||||
}
|
|
||||||
|
|
||||||
void NimbleBluetooth::shutdown()
|
void NimbleBluetooth::shutdown()
|
||||||
{
|
{
|
||||||
|
// No measurable power saving for ESP32 during light-sleep(?)
|
||||||
#ifndef ARCH_ESP32
|
#ifndef ARCH_ESP32
|
||||||
|
// Shutdown bluetooth for minimum power draw
|
||||||
LOG_INFO("Disable bluetooth");
|
LOG_INFO("Disable bluetooth");
|
||||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
pAdvertising->reset();
|
pAdvertising->reset();
|
||||||
@@ -736,6 +746,7 @@ void NimbleBluetooth::shutdown()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Proper shutdown for ESP32. Needs reboot to reverse.
|
||||||
void NimbleBluetooth::deinit()
|
void NimbleBluetooth::deinit()
|
||||||
{
|
{
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
@@ -749,17 +760,21 @@ void NimbleBluetooth::deinit()
|
|||||||
digitalWrite(BLE_LED, LOW);
|
digitalWrite(BLE_LED, LOW);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef NIMBLE_TWO
|
||||||
|
NimBLEDevice::deinit();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has initial setup been completed
|
||||||
bool NimbleBluetooth::isActive()
|
bool NimbleBluetooth::isActive()
|
||||||
{
|
{
|
||||||
return bleServer != nullptr;
|
return bleServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NimbleBluetooth::isConnected()
|
bool NimbleBluetooth::isConnected()
|
||||||
{
|
{
|
||||||
return bleServer && bleServer->getConnectedCount() > 0;
|
return bleServer->getConnectedCount() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NimbleBluetooth::getRssi()
|
int NimbleBluetooth::getRssi()
|
||||||
@@ -803,7 +818,7 @@ void NimbleBluetooth::setup()
|
|||||||
LOG_INFO("Init the NimBLE bluetooth module");
|
LOG_INFO("Init the NimBLE bluetooth module");
|
||||||
|
|
||||||
NimBLEDevice::init(getDeviceName());
|
NimBLEDevice::init(getDeviceName());
|
||||||
NimBLEDevice::setPower(9);
|
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||||
|
|
||||||
#if NIMBLE_ENABLE_2M_PHY && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6))
|
#if NIMBLE_ENABLE_2M_PHY && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6))
|
||||||
int mtuResult = NimBLEDevice::setMTU(kPreferredBleMtu);
|
int mtuResult = NimBLEDevice::setMTU(kPreferredBleMtu);
|
||||||
@@ -836,7 +851,11 @@ void NimbleBluetooth::setup()
|
|||||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
|
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
|
||||||
}
|
}
|
||||||
bleServer = NimBLEDevice::createServer();
|
bleServer = NimBLEDevice::createServer();
|
||||||
auto *serverCallbacks = new NimbleBluetoothServerCallback(this);
|
#ifdef NIMBLE_TWO
|
||||||
|
NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback(this);
|
||||||
|
#else
|
||||||
|
NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback();
|
||||||
|
#endif
|
||||||
bleServer->setCallbacks(serverCallbacks, true);
|
bleServer->setCallbacks(serverCallbacks, true);
|
||||||
setupService();
|
setupService();
|
||||||
startAdvertising();
|
startAdvertising();
|
||||||
@@ -881,7 +900,11 @@ void NimbleBluetooth::setupService()
|
|||||||
NimBLEService *batteryService = bleServer->createService(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
NimBLEService *batteryService = bleServer->createService(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
||||||
BatteryCharacteristic = batteryService->createCharacteristic( // 0x2A19 is the Battery Level characteristic)
|
BatteryCharacteristic = batteryService->createCharacteristic( // 0x2A19 is the Battery Level characteristic)
|
||||||
(uint16_t)0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY, 1);
|
(uint16_t)0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY, 1);
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
NimBLE2904 *batteryLevelDescriptor = BatteryCharacteristic->create2904();
|
NimBLE2904 *batteryLevelDescriptor = BatteryCharacteristic->create2904();
|
||||||
|
#else
|
||||||
|
NimBLE2904 *batteryLevelDescriptor = (NimBLE2904 *)BatteryCharacteristic->createDescriptor((uint16_t)0x2904);
|
||||||
|
#endif
|
||||||
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
||||||
batteryLevelDescriptor->setNamespace(1);
|
batteryLevelDescriptor->setNamespace(1);
|
||||||
batteryLevelDescriptor->setUnit(0x27ad);
|
batteryLevelDescriptor->setUnit(0x27ad);
|
||||||
@@ -889,12 +912,54 @@ void NimbleBluetooth::setupService()
|
|||||||
batteryService->start();
|
batteryService->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NimbleBluetooth::startAdvertising()
|
||||||
|
{
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
|
NimBLEExtAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
NimBLEExtAdvertisement legacyAdvertising;
|
||||||
|
|
||||||
|
legacyAdvertising.setLegacyAdvertising(true);
|
||||||
|
legacyAdvertising.setScannable(true);
|
||||||
|
legacyAdvertising.setConnectable(true);
|
||||||
|
legacyAdvertising.setFlags(BLE_HS_ADV_F_DISC_GEN);
|
||||||
|
if (powerStatus->getHasBattery() == 1) {
|
||||||
|
legacyAdvertising.setCompleteServices(NimBLEUUID((uint16_t)0x180f));
|
||||||
|
}
|
||||||
|
legacyAdvertising.setCompleteServices(NimBLEUUID(MESH_SERVICE_UUID));
|
||||||
|
legacyAdvertising.setMinInterval(500);
|
||||||
|
legacyAdvertising.setMaxInterval(1000);
|
||||||
|
|
||||||
|
NimBLEExtAdvertisement legacyScanResponse;
|
||||||
|
legacyScanResponse.setLegacyAdvertising(true);
|
||||||
|
legacyScanResponse.setConnectable(true);
|
||||||
|
legacyScanResponse.setName(getDeviceName());
|
||||||
|
|
||||||
|
if (!pAdvertising->setInstanceData(0, legacyAdvertising)) {
|
||||||
|
LOG_ERROR("BLE failed to set legacyAdvertising");
|
||||||
|
} else if (!pAdvertising->setScanResponseData(0, legacyScanResponse)) {
|
||||||
|
LOG_ERROR("BLE failed to set legacyScanResponse");
|
||||||
|
} else if (!pAdvertising->start(0, 0, 0)) {
|
||||||
|
LOG_ERROR("BLE failed to start legacyAdvertising");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
|
pAdvertising->reset();
|
||||||
|
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
|
||||||
|
pAdvertising->addServiceUUID(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
||||||
|
pAdvertising->start(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a level between 0-100, update the BLE attribute
|
/// Given a level between 0-100, update the BLE attribute
|
||||||
void updateBatteryLevel(uint8_t level)
|
void updateBatteryLevel(uint8_t level)
|
||||||
{
|
{
|
||||||
if ((config.bluetooth.enabled == true) && bleServer && nimbleBluetooth->isConnected()) {
|
if ((config.bluetooth.enabled == true) && bleServer && nimbleBluetooth->isConnected()) {
|
||||||
BatteryCharacteristic->setValue(&level, 1);
|
BatteryCharacteristic->setValue(&level, 1);
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
BatteryCharacteristic->notify(&level, 1, BLE_HS_CONN_HANDLE_NONE);
|
BatteryCharacteristic->notify(&level, 1, BLE_HS_CONN_HANDLE_NONE);
|
||||||
|
#else
|
||||||
|
BatteryCharacteristic->notify();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,7 +974,11 @@ void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length)
|
|||||||
if (!bleServer || !isConnected() || length > 512) {
|
if (!bleServer || !isConnected() || length > 512) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef NIMBLE_TWO
|
||||||
logRadioCharacteristic->notify(logMessage, length, BLE_HS_CONN_HANDLE_NONE);
|
logRadioCharacteristic->notify(logMessage, length, BLE_HS_CONN_HANDLE_NONE);
|
||||||
|
#else
|
||||||
|
logRadioCharacteristic->notify(logMessage, length, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearNVS()
|
void clearNVS()
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ class NimbleBluetooth : BluetoothApi
|
|||||||
bool isConnected();
|
bool isConnected();
|
||||||
int getRssi();
|
int getRssi();
|
||||||
void sendLog(const uint8_t *logMessage, size_t length);
|
void sendLog(const uint8_t *logMessage, size_t length);
|
||||||
|
#if defined(NIMBLE_TWO)
|
||||||
void startAdvertising();
|
void startAdvertising();
|
||||||
|
#endif
|
||||||
bool isDeInit = false;
|
bool isDeInit = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupService();
|
void setupService();
|
||||||
|
#if !defined(NIMBLE_TWO)
|
||||||
|
void startAdvertising();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void setBluetoothEnable(bool enable);
|
void setBluetoothEnable(bool enable);
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ void portduinoSetup()
|
|||||||
// RAK6421-13300-S1:aabbcc123456:5ba85807d92138b7519cfb60460573af:3061e8d8
|
// RAK6421-13300-S1:aabbcc123456:5ba85807d92138b7519cfb60460573af:3061e8d8
|
||||||
// <model string>:mac address :<16 random unique bytes in hexidecimal> : crc32
|
// <model string>:mac address :<16 random unique bytes in hexidecimal> : crc32
|
||||||
// crc32 is calculated on the eeprom string up to but not including the final colon
|
// crc32 is calculated on the eeprom string up to but not including the final colon
|
||||||
if (strlen(autoconf_product) < 6) {
|
if (strlen(autoconf_product) < 6 && portduino_config.i2cdev != "") {
|
||||||
try {
|
try {
|
||||||
char *mac_start = nullptr;
|
char *mac_start = nullptr;
|
||||||
char *devID_start = nullptr;
|
char *devID_start = nullptr;
|
||||||
@@ -869,4 +869,4 @@ void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault
|
|||||||
destPin.line = destPin.pin;
|
destPin.line = destPin.pin;
|
||||||
destPin.gpiochip = portduino_config.lora_default_gpiochip;
|
destPin.gpiochip = portduino_config.lora_default_gpiochip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -418,8 +418,9 @@ 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);
|
||||||
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
const int8_t hopsAway = getHopsAway(*mp);
|
||||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
|
if (hopsAway >= 0) {
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,8 +451,9 @@ 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);
|
||||||
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
const int8_t hopsAway = getHopsAway(*mp);
|
||||||
jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
|
if (hopsAway >= 0) {
|
||||||
|
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,8 +358,9 @@ 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;
|
||||||
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
const int8_t hopsAway = getHopsAway(*mp);
|
||||||
jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
|
if (hopsAway >= 0) {
|
||||||
|
jsonObj["hops_away"] = (unsigned int)(hopsAway);
|
||||||
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,8 +394,9 @@ 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;
|
||||||
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
|
const int8_t hopsAway = getHopsAway(*mp);
|
||||||
jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
|
if (hopsAway >= 0) {
|
||||||
|
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;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
[env:tbeam]
|
[env:tbeam]
|
||||||
extends = esp32_base
|
extends = esp32_base
|
||||||
board = ttgo-t-beam
|
board = ttgo-t-beam
|
||||||
board_level = extra
|
|
||||||
board_check = true
|
board_check = true
|
||||||
build_flags = ${esp32_base.build_flags}
|
build_flags = ${esp32_base.build_flags}
|
||||||
-D TBEAM_V10
|
-D TBEAM_V10
|
||||||
@@ -13,7 +13,7 @@ upload_speed = 921600
|
|||||||
|
|
||||||
[env:tbeam-displayshield]
|
[env:tbeam-displayshield]
|
||||||
extends = env:tbeam
|
extends = env:tbeam
|
||||||
|
board_level = extra
|
||||||
build_flags =
|
build_flags =
|
||||||
${env:tbeam.build_flags}
|
${env:tbeam.build_flags}
|
||||||
-D USE_ST7796
|
-D USE_ST7796
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ build_flags =
|
|||||||
-D HAS_BLUETOOTH=1
|
-D HAS_BLUETOOTH=1
|
||||||
-DCONFIG_BT_NIMBLE_EXT_ADV=1
|
-DCONFIG_BT_NIMBLE_EXT_ADV=1
|
||||||
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2
|
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=2
|
||||||
|
-D NIMBLE_TWO
|
||||||
monitor_speed=115200
|
monitor_speed=115200
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
NonBlockingRTTTL
|
NonBlockingRTTTL
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ static const uint8_t MOSI = 11;
|
|||||||
static const uint8_t MISO = 10;
|
static const uint8_t MISO = 10;
|
||||||
static const uint8_t SCK = 13;
|
static const uint8_t SCK = 13;
|
||||||
|
|
||||||
|
#define SPI_INTERFACES_COUNT 1
|
||||||
|
|
||||||
#define SPI_MOSI (11)
|
#define SPI_MOSI (11)
|
||||||
#define SPI_SCK (13)
|
#define SPI_SCK (13)
|
||||||
#define SPI_MISO (10)
|
#define SPI_MISO (10)
|
||||||
@@ -25,4 +27,51 @@ static const uint8_t SCK = 13;
|
|||||||
// LEDs
|
// LEDs
|
||||||
#define LED_BUILTIN LED_GREEN
|
#define LED_BUILTIN LED_GREEN
|
||||||
|
|
||||||
|
#ifdef _VARIANT_RAK3112_
|
||||||
|
/*
|
||||||
|
* Serial interfaces
|
||||||
|
*/
|
||||||
|
// TXD1 RXD1 on Base Board
|
||||||
|
#define PIN_SERIAL1_RX (44)
|
||||||
|
#define PIN_SERIAL1_TX (43)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal SPI to LoRa transceiver
|
||||||
|
*/
|
||||||
|
#define LORA_SX126X_SCK 5
|
||||||
|
#define LORA_SX126X_MISO 3
|
||||||
|
#define LORA_SX126X_MOSI 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Analog pins
|
||||||
|
*/
|
||||||
|
#define PIN_A0 (21)
|
||||||
|
#define PIN_A1 (14)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wire Interfaces
|
||||||
|
*/
|
||||||
|
#define WIRE_INTERFACES_COUNT 2
|
||||||
|
|
||||||
|
#define PIN_WIRE1_SDA (17)
|
||||||
|
#define PIN_WIRE1_SCL (18)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPIO's
|
||||||
|
*/
|
||||||
|
#define WB_IO1 21
|
||||||
|
#define WB_IO2 2
|
||||||
|
// #define WB_IO2 14
|
||||||
|
#define WB_IO3 41
|
||||||
|
#define WB_IO4 42
|
||||||
|
#define WB_IO5 38
|
||||||
|
#define WB_IO6 39
|
||||||
|
// #define WB_SW1 35 NC
|
||||||
|
#define WB_A0 1
|
||||||
|
#define WB_A1 2
|
||||||
|
#define WB_CS 12
|
||||||
|
#define WB_LED1 46
|
||||||
|
#define WB_LED2 45
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* Pins_Arduino_h */
|
#endif /* Pins_Arduino_h */
|
||||||
|
|||||||
@@ -9,3 +9,16 @@ build_flags =
|
|||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-D RAK3312
|
-D RAK3312
|
||||||
-I variants/esp32s3/rak3312
|
-I variants/esp32s3/rak3312
|
||||||
|
|
||||||
|
[env:rak3112]
|
||||||
|
extends = esp32s3_base
|
||||||
|
board = wiscore_rak3312
|
||||||
|
board_level = pr
|
||||||
|
board_check = true
|
||||||
|
upload_protocol = esptool
|
||||||
|
|
||||||
|
build_flags =
|
||||||
|
${esp32_base.build_flags}
|
||||||
|
-D RAK3312
|
||||||
|
-D _VARIANT_RAK3112_
|
||||||
|
-I variants/esp32s3/rak3312
|
||||||
|
|||||||
@@ -18,11 +18,6 @@
|
|||||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SX126X_POWER_EN (4)
|
|
||||||
|
|
||||||
#define PIN_POWER_EN PIN_3V3_EN
|
|
||||||
#define PIN_3V3_EN (14)
|
|
||||||
|
|
||||||
#define LED_GREEN 46
|
#define LED_GREEN 46
|
||||||
#define LED_BLUE 45
|
#define LED_BLUE 45
|
||||||
|
|
||||||
@@ -35,10 +30,30 @@
|
|||||||
|
|
||||||
#define LED_STATE_ON 1 // State when LED is litted
|
#define LED_STATE_ON 1 // State when LED is litted
|
||||||
|
|
||||||
|
#define BATTERY_PIN 1
|
||||||
|
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
|
||||||
|
|
||||||
|
#ifdef _VARIANT_RAK3112_ // Modular variant (stamp)
|
||||||
|
#define ADC_MULTIPLIER 2.11
|
||||||
|
|
||||||
|
#define BUTTON_NEED_PULLUP
|
||||||
|
|
||||||
|
#define HAS_SDCARD
|
||||||
|
#define SDCARD_USE_SPI1
|
||||||
|
#define SDCARD_CS SPI_CS
|
||||||
|
|
||||||
|
#define I2C_SDA1 PIN_WIRE1_SDA
|
||||||
|
#define I2C_SCL1 PIN_WIRE1_SCL
|
||||||
|
#else // Generic 3312 variant (40-pin standard connector)
|
||||||
|
#define ADC_MULTIPLIER 1.667
|
||||||
|
|
||||||
|
#define SX126X_POWER_EN (4)
|
||||||
|
|
||||||
|
#define PIN_POWER_EN PIN_3V3_EN
|
||||||
|
#define PIN_3V3_EN (14)
|
||||||
|
|
||||||
#define HAS_GPS 1
|
#define HAS_GPS 1
|
||||||
#define GPS_TX_PIN 43
|
#define GPS_TX_PIN 43
|
||||||
#define GPS_RX_PIN 44
|
#define GPS_RX_PIN 44
|
||||||
|
|
||||||
#define BATTERY_PIN 1
|
#endif
|
||||||
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
|
|
||||||
#define ADC_MULTIPLIER 1.667
|
|
||||||
@@ -100,3 +100,5 @@
|
|||||||
#define MODEM_DTR 8
|
#define MODEM_DTR 8
|
||||||
#define MODEM_RX 10
|
#define MODEM_RX 10
|
||||||
#define MODEM_TX 11
|
#define MODEM_TX 11
|
||||||
|
|
||||||
|
#define HAS_PHYSICAL_KEYBOARD 1
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#define SCREEN_TRANSITION_FRAMERATE 5
|
#define SCREEN_TRANSITION_FRAMERATE 5
|
||||||
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
||||||
#define USE_TFTDISPLAY 1
|
#define USE_TFTDISPLAY 1
|
||||||
|
#define HAS_PHYSICAL_KEYBOARD 1
|
||||||
|
|
||||||
#define HAS_TOUCHSCREEN 1
|
#define HAS_TOUCHSCREEN 1
|
||||||
#define SCREEN_TOUCH_INT 16
|
#define SCREEN_TOUCH_INT 16
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define SCREEN_TRANSITION_FRAMERATE 5
|
#define SCREEN_TRANSITION_FRAMERATE 5
|
||||||
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
||||||
#define USE_TFTDISPLAY 1
|
#define USE_TFTDISPLAY 1
|
||||||
|
#define HAS_PHYSICAL_KEYBOARD 1
|
||||||
|
|
||||||
#define I2C_SDA SDA
|
#define I2C_SDA SDA
|
||||||
#define I2C_SCL SCL
|
#define I2C_SCL SCL
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ lib_deps =
|
|||||||
${nrf52840_base.lib_deps}
|
${nrf52840_base.lib_deps}
|
||||||
# renovate: datasource=custom.pio depName=nRF52_PWM packageName=khoih-prog/library/nRF52_PWM
|
# renovate: datasource=custom.pio depName=nRF52_PWM packageName=khoih-prog/library/nRF52_PWM
|
||||||
khoih-prog/nRF52_PWM@1.0.1
|
khoih-prog/nRF52_PWM@1.0.1
|
||||||
# renovate: datasource=custom.pio depName=PCF8563 packageName=lewisxhe/library/PCF8563_Library
|
; # renovate: datasource=custom.pio depName=SensorLib packageName=lewisxhe/library/SensorLib
|
||||||
lewisxhe/PCF8563_Library@1.0.1
|
; lewisxhe/SensorLib@0.3.3
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ extern "C" {
|
|||||||
#define LR11X0_DIO_AS_RF_SWITCH
|
#define LR11X0_DIO_AS_RF_SWITCH
|
||||||
|
|
||||||
// PCF8563 RTC Module
|
// PCF8563 RTC Module
|
||||||
#define PCF8563_RTC 0x51
|
// REVISIT https://github.com/meshtastic/firmware/pull/9084
|
||||||
|
// #define PCF8563_RTC 0x51
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ build_flags = ${nrf52840_base.build_flags}
|
|||||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/ELECROW-ThinkNode-M6>
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/ELECROW-ThinkNode-M6>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${nrf52840_base.lib_deps}
|
${nrf52840_base.lib_deps}
|
||||||
# renovate: datasource=custom.pio depName=PCF8563 packageName=lewisxhe/library/PCF8563_Library
|
; # renovate: datasource=custom.pio depName=SensorLib packageName=lewisxhe/library/SensorLib
|
||||||
lewisxhe/PCF8563_Library@1.0.1
|
; lewisxhe/SensorLib@0.3.3
|
||||||
|
|||||||
@@ -41,3 +41,30 @@ void initVariant()
|
|||||||
pinMode(VDD_FLASH_EN, OUTPUT);
|
pinMode(VDD_FLASH_EN, OUTPUT);
|
||||||
digitalWrite(VDD_FLASH_EN, HIGH);
|
digitalWrite(VDD_FLASH_EN, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called from main-nrf52.cpp during the cpuDeepSleep() function
|
||||||
|
void variant_shutdown()
|
||||||
|
{
|
||||||
|
// This sets the pin to OUTPUT and LOW for the pins *not* in the if block.
|
||||||
|
for (int pin = 0; pin < 48; pin++) {
|
||||||
|
if (pin == PIN_GPS_EN || pin == ADC_CTRL || pin == PIN_BUTTON1 || pin == PIN_SPI_MISO || pin == PIN_SPI_MOSI ||
|
||||||
|
pin == PIN_SPI_SCK) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pinMode(pin, OUTPUT);
|
||||||
|
digitalWrite(pin, LOW);
|
||||||
|
if (pin >= 32) {
|
||||||
|
NRF_P1->DIRCLR = (1 << (pin - 32));
|
||||||
|
} else {
|
||||||
|
NRF_GPIO->DIRCLR = (1 << pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(PIN_GPS_EN, LOW);
|
||||||
|
digitalWrite(ADC_CTRL, LOW);
|
||||||
|
// digitalWrite(RTC_POWER, LOW);
|
||||||
|
|
||||||
|
nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
|
||||||
|
nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
|
||||||
|
nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,8 +44,10 @@ extern "C" {
|
|||||||
#define LED_BLUE -1
|
#define LED_BLUE -1
|
||||||
#define LED_CHARGE (12)
|
#define LED_CHARGE (12)
|
||||||
#define LED_PAIRING (7)
|
#define LED_PAIRING (7)
|
||||||
|
#define PIN_LED2 LED_PAIRING
|
||||||
|
|
||||||
#define LED_STATE_ON 1
|
#define LED_STATE_ON HIGH
|
||||||
|
#define LED_STATE_OFF LOW
|
||||||
|
|
||||||
// USB power detection
|
// USB power detection
|
||||||
#define EXT_PWR_DETECT (13)
|
#define EXT_PWR_DETECT (13)
|
||||||
@@ -119,7 +121,8 @@ static const uint8_t A0 = PIN_A0;
|
|||||||
#define PIN_SERIAL2_TX (24)
|
#define PIN_SERIAL2_TX (24)
|
||||||
|
|
||||||
// PCF8563 RTC Module
|
// PCF8563 RTC Module
|
||||||
#define PCF8563_RTC 0x51
|
// REVISIT https://github.com/meshtastic/firmware/pull/9084
|
||||||
|
// #define PCF8563_RTC 0x51
|
||||||
|
|
||||||
// SPI
|
// SPI
|
||||||
#define SPI_INTERFACES_COUNT 1
|
#define SPI_INTERFACES_COUNT 1
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ static const uint8_t A0 = PIN_A0;
|
|||||||
#define EXTERNAL_FLASH_USE_QSPI
|
#define EXTERNAL_FLASH_USE_QSPI
|
||||||
|
|
||||||
// Add a delay on startup to allow LoRa and GPS to power up
|
// Add a delay on startup to allow LoRa and GPS to power up
|
||||||
#define PIN_PWR_DELAY_MS 100
|
#define PERIPHERAL_WARMUP_MS 100
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lora radio
|
* Lora radio
|
||||||
@@ -178,4 +178,4 @@ static const uint8_t A0 = PIN_A0;
|
|||||||
* Arduino objects - C++ only
|
* Arduino objects - C++ only
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 2
|
major = 2
|
||||||
minor = 7
|
minor = 7
|
||||||
build = 18
|
build = 17
|
||||||
|
|||||||
Reference in New Issue
Block a user