mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-15 23:32:34 +00:00
Compare commits
213 Commits
v2.1.20.47
...
v2.2.4.3bc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bcab0e223 | ||
|
|
17617ce031 | ||
|
|
97f0c734e0 | ||
|
|
e943fffe8c | ||
|
|
ffcb131171 | ||
|
|
bb1fe7cad3 | ||
|
|
ad40493a39 | ||
|
|
ac62330e1c | ||
|
|
53f6a43661 | ||
|
|
7ad94da1c6 | ||
|
|
ecdb75aae0 | ||
|
|
7c98445ca3 | ||
|
|
b21368ecfa | ||
|
|
1a178c7d33 | ||
|
|
5d6f0ea6c4 | ||
|
|
5bd861f3d8 | ||
|
|
6d93fab495 | ||
|
|
6803fd7949 | ||
|
|
a61f969773 | ||
|
|
79cfc4b725 | ||
|
|
cf762bbd42 | ||
|
|
3d2c419d0d | ||
|
|
903f619609 | ||
|
|
2e3f762d3d | ||
|
|
a42266f74b | ||
|
|
a605c69eb4 | ||
|
|
282cc0b16a | ||
|
|
4ab67f3668 | ||
|
|
312028b161 | ||
|
|
ecd48db69c | ||
|
|
03dc36ea12 | ||
|
|
c2ae38405e | ||
|
|
2a1d8c40b4 | ||
|
|
e2441c425a | ||
|
|
00ffe73ebd | ||
|
|
3355019de3 | ||
|
|
5bb207d88b | ||
|
|
5453e4d123 | ||
|
|
7f1b58a222 | ||
|
|
39357b2686 | ||
|
|
d6b629ae04 | ||
|
|
7b1aeb60cd | ||
|
|
5c7c1cd253 | ||
|
|
8cfe130df3 | ||
|
|
feef86942d | ||
|
|
5f3a8b4924 | ||
|
|
0fcaaf39b0 | ||
|
|
a55eac5c20 | ||
|
|
b47c9c165a | ||
|
|
ecceb10910 | ||
|
|
6fc76103a0 | ||
|
|
f35c7be917 | ||
|
|
364364263b | ||
|
|
ef957bfac5 | ||
|
|
5d78795065 | ||
|
|
2dbdda204f | ||
|
|
4767bd5497 | ||
|
|
05efd68097 | ||
|
|
a90eef432f | ||
|
|
929b8f6209 | ||
|
|
5d76771fab | ||
|
|
91eb64d7b7 | ||
|
|
03fe4c629a | ||
|
|
144dfe9805 | ||
|
|
18899fd168 | ||
|
|
fcfd83bc89 | ||
|
|
a3d2b6166c | ||
|
|
fb5f2e48a5 | ||
|
|
d29c975e3c | ||
|
|
c44986127e | ||
|
|
6e0b6684ee | ||
|
|
84ddfea491 | ||
|
|
3d6fb13f9a | ||
|
|
54c48329c8 | ||
|
|
ede31a2080 | ||
|
|
9470d4694b | ||
|
|
2074c76780 | ||
|
|
9f6584bd67 | ||
|
|
dd69de9f32 | ||
|
|
616553ed72 | ||
|
|
1986267d65 | ||
|
|
1d0ac2caf7 | ||
|
|
746d7268a2 | ||
|
|
9a7777dbdb | ||
|
|
0fe99b0caa | ||
|
|
f9798b7dda | ||
|
|
23fb377fd7 | ||
|
|
4808a5c57f | ||
|
|
d25c368985 | ||
|
|
a5f3dea40b | ||
|
|
f026c3308c | ||
|
|
ed4e7a4cee | ||
|
|
95f67d70ea | ||
|
|
e3260c1d19 | ||
|
|
98f3be0665 | ||
|
|
dc31024764 | ||
|
|
5bbcb40f7a | ||
|
|
8218a729e0 | ||
|
|
cbc3e605dd | ||
|
|
94c41a4fed | ||
|
|
1afe9f75bd | ||
|
|
402f8ba524 | ||
|
|
04bbdc6b8a | ||
|
|
0084c0881d | ||
|
|
8552cc44b9 | ||
|
|
684cce7640 | ||
|
|
114eb0c952 | ||
|
|
bed2bfa074 | ||
|
|
0aef8703b6 | ||
|
|
f5d323fdd3 | ||
|
|
568cc259af | ||
|
|
42039e27e7 | ||
|
|
400b71c152 | ||
|
|
b1f6ff1280 | ||
|
|
cfe5c7f31d | ||
|
|
4e54bec525 | ||
|
|
e0bf15b80e | ||
|
|
26264fd908 | ||
|
|
794948d7e4 | ||
|
|
e9cbe54eca | ||
|
|
641d117106 | ||
|
|
5f38e79b8f | ||
|
|
b238aebe38 | ||
|
|
e05c8e60d9 | ||
|
|
f1bcc300d9 | ||
|
|
06a6a992c2 | ||
|
|
11be856507 | ||
|
|
7fe815a327 | ||
|
|
191a69dd26 | ||
|
|
9eeec6c083 | ||
|
|
c4474a7b99 | ||
|
|
0821cff1c8 | ||
|
|
b799b7bf62 | ||
|
|
90ec8eae6c | ||
|
|
ba172aae32 | ||
|
|
26338b8f2b | ||
|
|
939a359e7e | ||
|
|
5a5af4707c | ||
|
|
ef5e21d3da | ||
|
|
8a49221b7f | ||
|
|
76dc805184 | ||
|
|
297708a50b | ||
|
|
a61a4fad3e | ||
|
|
c66b68b0cc | ||
|
|
97d7a89644 | ||
|
|
04cba45c60 | ||
|
|
502a6596a3 | ||
|
|
5aedd84c7d | ||
|
|
b9c9f0f865 | ||
|
|
ffcc1a0275 | ||
|
|
3d697f8cf4 | ||
|
|
38c9a1ea07 | ||
|
|
0eefd0912f | ||
|
|
0cda8e6087 | ||
|
|
2cf648928a | ||
|
|
3cd7d8d6af | ||
|
|
702a83b525 | ||
|
|
32246850aa | ||
|
|
74650ca276 | ||
|
|
0141bbe772 | ||
|
|
049c587ca2 | ||
|
|
1a28225cd5 | ||
|
|
6bd870c454 | ||
|
|
c782380373 | ||
|
|
4fd756acd8 | ||
|
|
0b509c7e79 | ||
|
|
86af578df9 | ||
|
|
ff11506922 | ||
|
|
f35b422365 | ||
|
|
08f1ac785a | ||
|
|
146ed067a1 | ||
|
|
bdcf17a3f7 | ||
|
|
81edf363d7 | ||
|
|
96c6a20e03 | ||
|
|
3fbe2d771c | ||
|
|
ac9c81f6d1 | ||
|
|
2e7c95a110 | ||
|
|
490abdac96 | ||
|
|
b17436a023 | ||
|
|
b9ae63cb3c | ||
|
|
55701692fd | ||
|
|
3a24882e76 | ||
|
|
41b07de5a2 | ||
|
|
1745722dac | ||
|
|
849599cd8e | ||
|
|
bfc567ad89 | ||
|
|
b665786c77 | ||
|
|
e60a5f1cf2 | ||
|
|
6bdf67c9be | ||
|
|
bbfd62c47e | ||
|
|
a07e30544d | ||
|
|
9716bd8bec | ||
|
|
c2168dd450 | ||
|
|
66c71250b8 | ||
|
|
5c438ae792 | ||
|
|
cdf44ce7fa | ||
|
|
d70bd23260 | ||
|
|
b42ead4400 | ||
|
|
b2704a0082 | ||
|
|
9b94701699 | ||
|
|
61661aed50 | ||
|
|
3a25d6d3b3 | ||
|
|
fd4e9daa7f | ||
|
|
b6f7b7fa47 | ||
|
|
a92a960682 | ||
|
|
5d2ab65a81 | ||
|
|
f3b7f7251c | ||
|
|
2f60bbe5f2 | ||
|
|
0261754269 | ||
|
|
e6fc2af21f | ||
|
|
ae41944a89 | ||
|
|
62259583e6 | ||
|
|
c5d87fe581 |
4
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
4
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
@@ -37,7 +37,9 @@ body:
|
||||
- T-Lora v1
|
||||
- T-Lora v1.3
|
||||
- T-Lora v2 1.6
|
||||
- T-Deck
|
||||
- T-Echo
|
||||
- T-Watch
|
||||
- Rak4631
|
||||
- Rak11200
|
||||
- Rak11310
|
||||
@@ -45,6 +47,8 @@ body:
|
||||
- Heltec v2
|
||||
- Heltec v2.1
|
||||
- Heltec V3
|
||||
- Heltec Wireless Paper
|
||||
- Heltec Wireless Tracker
|
||||
- Raspberry Pi Pico (W)
|
||||
- Relay v1
|
||||
- Relay v2
|
||||
|
||||
16
.github/workflows/build_esp32.yml
vendored
16
.github/workflows/build_esp32.yml
vendored
@@ -17,11 +17,11 @@ jobs:
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
repo: meshtastic/web
|
||||
file: build.tar
|
||||
target: build.tar
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
@@ -40,11 +40,11 @@ jobs:
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/firmware-ota"
|
||||
file: "firmware.bin"
|
||||
target: "release/bleota.bin"
|
||||
repo: meshtastic/firmware-ota
|
||||
file: firmware.bin
|
||||
target: release/bleota.bin
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
|
||||
16
.github/workflows/build_esp32_s3.yml
vendored
16
.github/workflows/build_esp32_s3.yml
vendored
@@ -17,11 +17,11 @@ jobs:
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
repo: meshtastic/web
|
||||
file: build.tar
|
||||
target: build.tar
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
@@ -38,11 +38,11 @@ jobs:
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/firmware-ota"
|
||||
file: "firmware-s3.bin"
|
||||
target: "release/bleota-s3.bin"
|
||||
repo: meshtastic/firmware-ota
|
||||
file: firmware-s3.bin
|
||||
target: release/bleota-s3.bin
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
|
||||
8
.github/workflows/main_matrix.yml
vendored
8
.github/workflows/main_matrix.yml
vendored
@@ -1,4 +1,7 @@
|
||||
name: CI
|
||||
#concurrency:
|
||||
# group: ${{ github.ref }}
|
||||
# cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||
on:
|
||||
# # Triggers the workflow on push but only for the master branch
|
||||
push:
|
||||
@@ -46,7 +49,7 @@ jobs:
|
||||
|
||||
- name: Trunk Check
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
uses: trunk-io/trunk-action@v1
|
||||
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
|
||||
|
||||
- name: Check ${{ matrix.board }}
|
||||
run: bin/check-all.sh ${{ matrix.board }}
|
||||
@@ -92,6 +95,7 @@ jobs:
|
||||
- board: tlora-t3s3-v1
|
||||
- board: t-watch-s3
|
||||
- board: t-deck
|
||||
- board: picomputer-s3
|
||||
uses: ./.github/workflows/build_esp32_s3.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
@@ -108,6 +112,7 @@ jobs:
|
||||
- board: t-echo
|
||||
- board: pca10059_diy_eink
|
||||
- board: feather_diy
|
||||
- board: nano-g2-ultra
|
||||
uses: ./.github/workflows/build_nrf52.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
@@ -255,6 +260,7 @@ jobs:
|
||||
retention-days: 30
|
||||
|
||||
- name: Create request artifacts
|
||||
continue-on-error: true # FIXME: Why are we getting 502, but things still work?
|
||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||
uses: gavv/pull-request-artifacts@v1.1.0
|
||||
with:
|
||||
|
||||
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@@ -14,6 +14,6 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1
|
||||
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
|
||||
with:
|
||||
trunk-token: ${{ secrets.TRUNK_TOKEN }}
|
||||
|
||||
2
.trunk/.gitignore
vendored
2
.trunk/.gitignore
vendored
@@ -5,4 +5,4 @@
|
||||
plugins
|
||||
user_trunk.yaml
|
||||
user.yaml
|
||||
shims
|
||||
tools
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
version: 0.1
|
||||
cli:
|
||||
version: 1.9.1
|
||||
version: 1.13.0
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v0.0.17
|
||||
ref: v1.1.1
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- taplo@0.7.0
|
||||
- ruff@0.0.265
|
||||
- yamllint@1.31.0
|
||||
- bandit@1.7.5
|
||||
- checkov@2.4.1
|
||||
- terrascan@1.18.3
|
||||
- trivy@0.44.1
|
||||
- trufflehog@3.48.0
|
||||
- taplo@0.8.1
|
||||
- ruff@0.0.284
|
||||
- yamllint@1.32.0
|
||||
- isort@5.12.0
|
||||
- markdownlint@0.34.0
|
||||
- markdownlint@0.35.0
|
||||
- oxipng@8.0.0
|
||||
- svgo@3.0.2
|
||||
- actionlint@1.6.24
|
||||
- flake8@6.0.0
|
||||
- actionlint@1.6.25
|
||||
- flake8@6.1.0
|
||||
- hadolint@2.12.0
|
||||
- shfmt@3.5.0
|
||||
- shfmt@3.6.0
|
||||
- shellcheck@0.9.0
|
||||
- black@23.3.0
|
||||
- black@23.7.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.16.3
|
||||
- clang-format@14.0.0
|
||||
- prettier@2.8.8
|
||||
- gitleaks@8.17.0
|
||||
- clang-format@16.0.3
|
||||
- prettier@3.0.2
|
||||
disabled:
|
||||
- taplo@0.7.0
|
||||
- taplo@0.8.1
|
||||
- shellcheck@0.9.0
|
||||
- shfmt@3.5.0
|
||||
- shfmt@3.6.0
|
||||
- oxipng@8.0.0
|
||||
- actionlint@1.6.22
|
||||
- markdownlint@0.34.0
|
||||
- markdownlint@0.35.0
|
||||
- hadolint@2.12.0
|
||||
- svgo@3.0.2
|
||||
runtimes:
|
||||
|
||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -6,4 +6,4 @@
|
||||
"platformio.platformio-ide",
|
||||
"trunk.io"
|
||||
],
|
||||
}
|
||||
}
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "trunk.io"
|
||||
"editor.defaultFormatter": "trunk.io",
|
||||
"trunk.enableWindows": true
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ build_flags =
|
||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
-DSERIAL_BUFFER_SIZE=4096
|
||||
;-DDEBUG_HEAP
|
||||
|
||||
lib_deps =
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
platform = platformio/nordicnrf52@^10.0.0
|
||||
platform = platformio/nordicnrf52@^10.1.0
|
||||
extends = arduino_base
|
||||
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
${arduino_base.build_flags}
|
||||
-DSERIAL_BUFFER_SIZE=1024
|
||||
-Wno-unused-variable
|
||||
-Isrc/platform/nrf52
|
||||
|
||||
build_src_filter =
|
||||
|
||||
@@ -4,23 +4,23 @@
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
VERSION=$(bin/buildinfo.py long)
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
else
|
||||
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo pca10059_diy_eink"
|
||||
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo pca10059_diy_eink"
|
||||
fi
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
CHECK=""
|
||||
for BOARD in $BOARDS; do
|
||||
CHECK="${CHECK} -e ${BOARD}"
|
||||
CHECK="${CHECK} -e ${BOARD}"
|
||||
done
|
||||
|
||||
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=low --fail-on-defect=medium --fail-on-defect=high
|
||||
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=medium --fail-on-defect=high
|
||||
|
||||
@@ -32,7 +32,7 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
|
||||
@REM Account for S3 board's different OTA partition
|
||||
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% (
|
||||
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||
) else (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
|
||||
|
||||
@@ -50,7 +50,7 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
# Account for S3 board's different OTA partition
|
||||
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ]; then
|
||||
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||
else
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
|
||||
51
boards/nano-g2-ultra.json
Normal file
51
boards/nano-g2-ultra.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x8029"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"],
|
||||
["0x239A", "0x802A"]
|
||||
],
|
||||
"usb_product": "BQ nRF52840",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "nano-g2-ultra",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "BQ nRF52840",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra",
|
||||
"vendor": "BQ Consulting"
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dio",
|
||||
"hwids": [["0X303A", "0x1001"]],
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "t-watch-s3"
|
||||
},
|
||||
|
||||
@@ -88,7 +88,7 @@ check_flags =
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
mprograms/QMC5883LCompass@^1.1.1
|
||||
mprograms/QMC5883LCompass@^1.2.0
|
||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
|
||||
|
||||
@@ -107,8 +107,8 @@ lib_deps =
|
||||
[environmental_base]
|
||||
lib_deps =
|
||||
adafruit/Adafruit BusIO@^1.11.4
|
||||
adafruit/Adafruit Unified Sensor@^1.1.9
|
||||
adafruit/Adafruit BMP280 Library@^2.6.6
|
||||
adafruit/Adafruit Unified Sensor@^1.1.11
|
||||
adafruit/Adafruit BMP280 Library@^2.6.8
|
||||
adafruit/Adafruit BME280 Library@^2.2.2
|
||||
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
|
||||
boschsensortec/BME68x Sensor Library@^1.1.40407
|
||||
@@ -117,7 +117,7 @@ lib_deps =
|
||||
adafruit/Adafruit INA219@^1.2.0
|
||||
adafruit/Adafruit SHTC3 Library@^1.0.0
|
||||
adafruit/Adafruit LPS2X@^2.0.4
|
||||
adafruit/Adafruit SHT31 Library@^2.2.0
|
||||
adafruit/Adafruit SHT31 Library@^2.2.2
|
||||
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
|
||||
adafruit/Adafruit MPU6050@^2.2.4
|
||||
adafruit/Adafruit LIS3DH@^1.2.4
|
||||
|
||||
Submodule protobufs updated: f17298c2b0...826dfb7604
@@ -101,23 +101,8 @@ class ButtonThread : public concurrency::OSThread
|
||||
#endif
|
||||
// if (!canSleep) LOG_DEBUG("Suppressing sleep!\n");
|
||||
// else LOG_DEBUG("sleep ok\n");
|
||||
#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
int x, y = 0;
|
||||
screen->getTouch(&x, &y);
|
||||
if (x > 0 && y > 0) {
|
||||
#ifdef T_WATCH_S3
|
||||
drv.setWaveform(0, 75);
|
||||
drv.setWaveform(1, 0); // end waveform
|
||||
drv.go();
|
||||
#endif
|
||||
LOG_DEBUG("touch %d %d\n", x, y);
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
return 150; // Check for next touch every in 150ms
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return 5;
|
||||
return 50;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @file FSCommon.cpp
|
||||
* @brief This file contains functions for common filesystem operations such as copying, renaming, listing and deleting files and
|
||||
* directories.
|
||||
*
|
||||
* The functions in this file are used to perform common filesystem operations such as copying, renaming, listing and deleting
|
||||
* files and directories. These functions are used in the Meshtastic-device project to manage files and directories on the
|
||||
* device's filesystem.
|
||||
*
|
||||
*/
|
||||
#include "FSCommon.h"
|
||||
#include "configuration.h"
|
||||
|
||||
@@ -14,6 +24,13 @@ SPIClass SPI1(HSPI);
|
||||
|
||||
#endif // HAS_SDCARD
|
||||
|
||||
/**
|
||||
* @brief Copies a file from one location to another.
|
||||
*
|
||||
* @param from The path of the source file.
|
||||
* @param to The path of the destination file.
|
||||
* @return true if the file was successfully copied, false otherwise.
|
||||
*/
|
||||
bool copyFile(const char *from, const char *to)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -43,6 +60,14 @@ bool copyFile(const char *from, const char *to)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a file from pathFrom to pathTo.
|
||||
*
|
||||
* @param pathFrom The original path of the file.
|
||||
* @param pathTo The new path of the file.
|
||||
*
|
||||
* @return True if the file was successfully renamed, false otherwise.
|
||||
*/
|
||||
bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -59,6 +84,13 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the contents of a directory.
|
||||
*
|
||||
* @param dirname The name of the directory to list.
|
||||
* @param levels The number of levels of subdirectories to list.
|
||||
* @param del Whether or not to delete the contents of the directory after listing.
|
||||
*/
|
||||
void listDir(const char *dirname, uint8_t levels, bool del = false)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -154,6 +186,13 @@ void listDir(const char *dirname, uint8_t levels, bool del = false)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes a directory and all its contents.
|
||||
*
|
||||
* This function recursively removes a directory and all its contents, including subdirectories and files.
|
||||
*
|
||||
* @param dirname The name of the directory to remove.
|
||||
*/
|
||||
void rmDir(const char *dirname)
|
||||
{
|
||||
#ifdef FSCom
|
||||
@@ -182,6 +221,9 @@ void fsInit()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the SD card and mounts the file system.
|
||||
*/
|
||||
void setupSDCard()
|
||||
{
|
||||
#ifdef HAS_SDCARD
|
||||
@@ -212,4 +254,4 @@ void setupSDCard()
|
||||
LOG_DEBUG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
|
||||
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,16 @@ static void IRAM_ATTR onTimer()
|
||||
(*tCallback)(tParam1, tParam2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a hardware callback function to be executed after a specified delay.
|
||||
*
|
||||
* @param callback The function to be executed.
|
||||
* @param param1 The first parameter to be passed to the function.
|
||||
* @param param2 The second parameter to be passed to the function.
|
||||
* @param delayMsec The delay time in milliseconds before the function is executed.
|
||||
*
|
||||
* @return True if the function was successfully scheduled, false otherwise.
|
||||
*/
|
||||
bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec)
|
||||
{
|
||||
if (!timer) {
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
/**
|
||||
* @file Power.cpp
|
||||
* @brief This file contains the implementation of the Power class, which is responsible for managing power-related functionality
|
||||
* of the device. It includes battery level sensing, power management unit (PMU) control, and power state machine management. The
|
||||
* Power class is used by the main device class to manage power-related functionality.
|
||||
*
|
||||
* The file also includes implementations of various battery level sensors, such as the AnalogBatteryLevel class, which assumes
|
||||
* the battery voltage is attached via a voltage-divider to an analog input.
|
||||
*
|
||||
* This file is part of the Meshtastic project.
|
||||
* For more information, see: https://meshtastic.org/
|
||||
*/
|
||||
#include "power.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "buzz/buzz.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "meshUtils.h"
|
||||
#include "sleep.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef DEBUG_HEAP_MQTT
|
||||
#include "mqtt/MQTT.h"
|
||||
@@ -209,10 +221,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() override
|
||||
{
|
||||
return getBatteryPercent() != -1;
|
||||
}
|
||||
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
|
||||
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
@@ -233,10 +242,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
|
||||
/// Assume charging if we have a battery and external power is connected.
|
||||
/// we can't be smart enough to say 'full'?
|
||||
virtual bool isCharging() override
|
||||
{
|
||||
return isBatteryConnect() && isVbusIn();
|
||||
}
|
||||
virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); }
|
||||
|
||||
private:
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
@@ -366,6 +372,11 @@ bool Power::analogInit()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Power class.
|
||||
*
|
||||
* @return true if the setup was successful, false otherwise.
|
||||
*/
|
||||
bool Power::setup()
|
||||
{
|
||||
bool found = axpChipInit();
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file PowerFSM.cpp
|
||||
* @brief Implements the finite state machine for power management.
|
||||
*
|
||||
* This file contains the implementation of the finite state machine (FSM) for power management.
|
||||
* The FSM controls the power states of the device, including SDS (shallow deep sleep), LS (light sleep),
|
||||
* NB (normal mode), and POWER (powered mode). The FSM also handles transitions between states and
|
||||
* actions to be taken upon entering or exiting each state.
|
||||
*/
|
||||
#include "PowerFSM.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
@@ -137,7 +146,10 @@ static void nbEnter()
|
||||
{
|
||||
LOG_DEBUG("Enter state: NB\n");
|
||||
screen->setOn(false);
|
||||
#ifdef ARCH_ESP32
|
||||
// Only ESP32 should turn off bluetooth
|
||||
setBluetoothEnable(false);
|
||||
#endif
|
||||
|
||||
// FIXME - check if we already have packets for phone and immediately trigger EVENT_PACKETS_FOR_PHONE
|
||||
}
|
||||
@@ -158,12 +170,14 @@ static void serialEnter()
|
||||
|
||||
static void serialExit()
|
||||
{
|
||||
// Turn bluetooth back on when we leave serial stream API
|
||||
setBluetoothEnable(true);
|
||||
screen->print("Serial disconnected\n");
|
||||
}
|
||||
|
||||
static void powerEnter()
|
||||
{
|
||||
LOG_DEBUG("Enter state: POWER\n");
|
||||
// LOG_DEBUG("Enter state: POWER\n");
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||
LOG_INFO("Loss of power in Powered\n");
|
||||
@@ -242,7 +256,11 @@ void PowerFSM_setup()
|
||||
|
||||
// wake timer expired or a packet arrived
|
||||
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
|
||||
#ifdef ARCH_ESP32
|
||||
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
||||
#else // Don't go into a no-bluetooth state on low power platforms
|
||||
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
||||
#endif
|
||||
|
||||
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from
|
||||
// light sleep we _always_ transition to NB or dark and
|
||||
@@ -279,7 +297,8 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||
|
||||
@@ -21,7 +21,7 @@ class PowerFSMThread : public OSThread
|
||||
|
||||
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
|
||||
/// cpu for serial rx - FIXME)
|
||||
auto state = powerFSM.getState();
|
||||
const auto state = powerFSM.getState();
|
||||
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
|
||||
|
||||
if (powerStatus->getHasUSB()) {
|
||||
|
||||
@@ -18,6 +18,12 @@ NoopPrint noopPrint;
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
extern Syslog syslog;
|
||||
#endif
|
||||
void RedirectablePrint::rpInit()
|
||||
{
|
||||
#ifdef HAS_FREE_RTOS
|
||||
inDebugPrint = xSemaphoreCreateMutexStatic(&this->_MutexStorageSpace);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RedirectablePrint::setDestination(Print *_dest)
|
||||
{
|
||||
@@ -66,9 +72,12 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
return 0;
|
||||
}
|
||||
size_t r = 0;
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
if (inDebugPrint != nullptr && xSemaphoreTake(inDebugPrint, portMAX_DELAY) == pdTRUE) {
|
||||
#else
|
||||
if (!inDebugPrint) {
|
||||
inDebugPrint = true;
|
||||
#endif
|
||||
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
@@ -141,7 +150,11 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
va_end(arg);
|
||||
|
||||
isContinuationMessage = !hasNewline;
|
||||
#ifdef HAS_FREE_RTOS
|
||||
xSemaphoreGive(inDebugPrint);
|
||||
#else
|
||||
inDebugPrint = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../freertosinc.h"
|
||||
#include <Print.h>
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
@@ -16,14 +17,19 @@ class RedirectablePrint : public Print
|
||||
/// Used to allow multiple logDebug messages to appear on a single log line
|
||||
bool isContinuationMessage = false;
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
SemaphoreHandle_t inDebugPrint = nullptr;
|
||||
StaticSemaphore_t _MutexStorageSpace;
|
||||
#else
|
||||
volatile bool inDebugPrint = false;
|
||||
|
||||
#endif
|
||||
public:
|
||||
explicit RedirectablePrint(Print *_dest) : dest(_dest) {}
|
||||
|
||||
/**
|
||||
* Set a new destination
|
||||
*/
|
||||
void rpInit();
|
||||
void setDestination(Print *dest);
|
||||
|
||||
virtual size_t write(uint8_t c);
|
||||
@@ -54,4 +60,4 @@ class NoopPrint : public Print
|
||||
/**
|
||||
* A printer that doesn't go anywhere
|
||||
*/
|
||||
extern NoopPrint noopPrint;
|
||||
extern NoopPrint noopPrint;
|
||||
@@ -12,6 +12,7 @@ SerialConsole *console;
|
||||
void consoleInit()
|
||||
{
|
||||
new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
|
||||
DEBUG_PORT.rpInit(); // Simply sets up semaphore
|
||||
}
|
||||
|
||||
void consolePrintf(const char *format, ...)
|
||||
|
||||
@@ -15,4 +15,6 @@ enum class Cmd {
|
||||
PRINT,
|
||||
START_SHUTDOWN_SCREEN,
|
||||
START_REBOOT_SCREEN,
|
||||
SHOW_PREV_FRAME,
|
||||
SHOW_NEXT_FRAME
|
||||
};
|
||||
@@ -98,8 +98,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Define if screen should be mirrored left to right
|
||||
// #define SCREEN_MIRROR
|
||||
|
||||
// The m5stack I2C Keyboard (also RAK14004)
|
||||
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
|
||||
#define CARDKB_ADDR 0x5F
|
||||
#define TDECK_KB_ADDR 0x55
|
||||
#define BBQ10_KB_ADDR 0x1F
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SENSOR
|
||||
@@ -146,6 +148,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define GPS_THREAD_INTERVAL 100
|
||||
#endif
|
||||
|
||||
// convert 24-bit color to 16-bit (56K)
|
||||
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
|
||||
|
||||
/* Step #1: offer chance for variant-specific defines */
|
||||
#include "variant.h"
|
||||
|
||||
@@ -173,6 +178,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef HAS_BUTTON
|
||||
#define HAS_BUTTON 0
|
||||
#endif
|
||||
#ifndef HAS_TRACKBALL
|
||||
#define HAS_TRACKBALL 0
|
||||
#endif
|
||||
#ifndef HAS_TOUCHSCREEN
|
||||
#define HAS_TOUCHSCREEN 0
|
||||
#endif
|
||||
#ifndef HAS_TELEMETRY
|
||||
#define HAS_TELEMETRY 0
|
||||
#endif
|
||||
|
||||
@@ -30,8 +30,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||
{
|
||||
ScanI2C::DeviceType types[] = {CARDKB, RAK14004};
|
||||
return firstOfOrNONE(2, types);
|
||||
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004};
|
||||
return firstOfOrNONE(4, types);
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
||||
|
||||
@@ -16,6 +16,8 @@ class ScanI2C
|
||||
RTC_RV3028,
|
||||
RTC_PCF8563,
|
||||
CARDKB,
|
||||
TDECKKB,
|
||||
BBQ10KB,
|
||||
RAK14004,
|
||||
PMU_AXP192_AXP2101,
|
||||
BME_680,
|
||||
|
||||
@@ -212,6 +212,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
}
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
|
||||
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found\n");
|
||||
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
|
||||
#ifdef HAS_NCP5623
|
||||
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
|
||||
|
||||
421
src/gps/GPS.cpp
421
src/gps/GPS.cpp
@@ -4,6 +4,10 @@
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "meshUtils.h"
|
||||
#endif
|
||||
|
||||
#ifndef GPS_RESET_MODE
|
||||
#define GPS_RESET_MODE HIGH
|
||||
#endif
|
||||
@@ -43,13 +47,50 @@ void GPS::UBXChecksum(byte *message, size_t length)
|
||||
message[length - 1] = CK_B;
|
||||
}
|
||||
|
||||
bool GPS::getACK(uint8_t class_id, uint8_t msg_id)
|
||||
GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
||||
{
|
||||
uint8_t buffer[768] = {0};
|
||||
uint8_t b;
|
||||
int bytesRead = 0;
|
||||
uint32_t startTimeout = millis() + waitMillis;
|
||||
while (millis() < startTimeout) {
|
||||
if (_serial_gps->available()) {
|
||||
b = _serial_gps->read();
|
||||
buffer[bytesRead] = b;
|
||||
bytesRead++;
|
||||
if ((bytesRead == 767) || (b == '\r')) {
|
||||
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
||||
#ifdef GPS_DEBUG
|
||||
buffer[bytesRead] = '\0';
|
||||
LOG_DEBUG("%s\r", (char *)buffer);
|
||||
#endif
|
||||
return GNSS_RESPONSE_OK;
|
||||
} else {
|
||||
#ifdef GPS_DEBUG
|
||||
buffer[bytesRead] = '\0';
|
||||
LOG_INFO("Bytes read:%s\n", (char *)buffer);
|
||||
#endif
|
||||
bytesRead = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef GPS_DEBUG
|
||||
buffer[bytesRead] = '\0';
|
||||
LOG_INFO("Bytes read:%s\n", (char *)buffer);
|
||||
#endif
|
||||
return GNSS_RESPONSE_NONE;
|
||||
}
|
||||
|
||||
GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t ack = 0;
|
||||
const uint8_t ackP[2] = {class_id, msg_id};
|
||||
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned long startTime = millis();
|
||||
uint32_t startTime = millis();
|
||||
const char frame_errors[] = "More than 100 frame errors";
|
||||
int sCounter = 0;
|
||||
|
||||
for (int j = 2; j < 6; j++) {
|
||||
buf[8] += buf[j];
|
||||
@@ -62,28 +103,46 @@ bool GPS::getACK(uint8_t class_id, uint8_t msg_id)
|
||||
buf[9] += buf[8];
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (millis() - startTime < waitMillis) {
|
||||
if (ack > 9) {
|
||||
// LOG_INFO("Got ACK for class %02X message %02X\n", class_id, msg_id);
|
||||
return true; // ACK received
|
||||
}
|
||||
if (millis() - startTime > 3000) {
|
||||
LOG_WARN("No response for class %02X message %02X\n", class_id, msg_id);
|
||||
return false; // No response received within 3 seconds
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG("\n");
|
||||
LOG_INFO("Got ACK for class %02X message %02X in %d millis.\n", class_id, msg_id, millis() - startTime);
|
||||
#endif
|
||||
return GNSS_RESPONSE_OK; // ACK received
|
||||
}
|
||||
if (_serial_gps->available()) {
|
||||
b = _serial_gps->read();
|
||||
if (b == frame_errors[sCounter]) {
|
||||
sCounter++;
|
||||
if (sCounter == 26) {
|
||||
return GNSS_RESPONSE_FRAME_ERRORS;
|
||||
}
|
||||
} else {
|
||||
sCounter = 0;
|
||||
}
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG("%02X", b);
|
||||
#endif
|
||||
if (b == buf[ack]) {
|
||||
ack++;
|
||||
} else {
|
||||
ack = 0; // Reset the acknowledgement counter
|
||||
if (buf[3] == 0x00) { // UBX-ACK-NAK message
|
||||
if (ack == 3 && b == 0x00) { // UBX-ACK-NAK message
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG("\n");
|
||||
#endif
|
||||
LOG_WARN("Got NAK for class %02X message %02X\n", class_id, msg_id);
|
||||
return false; // NAK received
|
||||
return GNSS_RESPONSE_NAK; // NAK received
|
||||
}
|
||||
ack = 0; // Reset the acknowledgement counter
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG("\n");
|
||||
LOG_WARN("No response for class %02X message %02X\n", class_id, msg_id);
|
||||
#endif
|
||||
return GNSS_RESPONSE_NONE; // No response received within timeout
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,14 +154,14 @@ bool GPS::getACK(uint8_t class_id, uint8_t msg_id)
|
||||
* @param requestedID: request message ID constant
|
||||
* @retval length of payload message
|
||||
*/
|
||||
int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID)
|
||||
int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis)
|
||||
{
|
||||
uint16_t ubxFrameCounter = 0;
|
||||
uint32_t startTime = millis();
|
||||
uint16_t needRead;
|
||||
|
||||
while (millis() - startTime < 1200) {
|
||||
while (_serial_gps->available()) {
|
||||
while (millis() - startTime < waitMillis) {
|
||||
if (_serial_gps->available()) {
|
||||
int c = _serial_gps->read();
|
||||
switch (ubxFrameCounter) {
|
||||
case 0:
|
||||
@@ -144,8 +203,6 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
||||
// Payload length msb
|
||||
needRead |= (c << 8);
|
||||
ubxFrameCounter++;
|
||||
break;
|
||||
case 6:
|
||||
// Check for buffer overflow
|
||||
if (needRead >= size) {
|
||||
ubxFrameCounter = 0;
|
||||
@@ -155,6 +212,10 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
||||
ubxFrameCounter = 0;
|
||||
} else {
|
||||
// return payload length
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_INFO("Got ACK for class %02X message %02X in %d millis.\n", requestedClass, requestedID,
|
||||
millis() - startTime);
|
||||
#endif
|
||||
return needRead;
|
||||
}
|
||||
break;
|
||||
@@ -164,6 +225,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
||||
}
|
||||
}
|
||||
}
|
||||
// LOG_WARN("No response for class %02X message %02X\n", requestedClass, requestedID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -174,7 +236,7 @@ bool GPS::setupGPS()
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// In esp32 framework, setRxBufferSize needs to be initialized before Serial
|
||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||
_serial_gps->setRxBufferSize(SERIAL_BUFFER_SIZE); // the default is 256
|
||||
#endif
|
||||
|
||||
// if the overrides are not dialled in, set them from the board definitions, if they exist
|
||||
@@ -188,8 +250,8 @@ bool GPS::setupGPS()
|
||||
config.position.tx_gpio = GPS_TX_PIN;
|
||||
#endif
|
||||
|
||||
//#define BAUD_RATE 115200
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
// #define BAUD_RATE 115200
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
#if defined(ARCH_ESP32)
|
||||
if (config.position.rx_gpio) {
|
||||
LOG_DEBUG("Using GPIO%d for GPS RX\n", config.position.rx_gpio);
|
||||
@@ -203,7 +265,21 @@ bool GPS::setupGPS()
|
||||
/*
|
||||
* T-Beam-S3-Core will be preset to use gps Probe here, and other boards will not be changed first
|
||||
*/
|
||||
gnssModel = probe();
|
||||
#if defined(GPS_UC6580)
|
||||
_serial_gps->updateBaudRate(115200);
|
||||
gnssModel = GNSS_MODEL_UC6850;
|
||||
#else
|
||||
for (int serialSpeed : {9600, 4800, 38400, 57600, 115200}) {
|
||||
LOG_DEBUG("Probing for GPS at %d \n", serialSpeed);
|
||||
gnssModel = probe(serialSpeed);
|
||||
if (gnssModel != GNSS_MODEL_UNKNOWN)
|
||||
break;
|
||||
}
|
||||
if (gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
LOG_DEBUG("No GPS found, retrying at 9600 baud.\n");
|
||||
gnssModel = probe(9600);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gnssModel == GNSS_MODEL_MTK) {
|
||||
/*
|
||||
@@ -213,8 +289,8 @@ bool GPS::setupGPS()
|
||||
// _serial_gps->begin(9600); //The baud rate of 9600 has been initialized at the beginning of setupGPS, this line
|
||||
// is the redundant part delay(250);
|
||||
|
||||
// Initialize the L76K Chip, use GPS + GLONASS
|
||||
_serial_gps->write("$PCAS04,5*1C\r\n");
|
||||
// Initialize the L76K Chip, use GPS + GLONASS + BEIDOU
|
||||
_serial_gps->write("$PCAS04,7*1E\r\n");
|
||||
delay(250);
|
||||
// only ask for RMC and GGA
|
||||
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
|
||||
@@ -228,46 +304,88 @@ bool GPS::setupGPS()
|
||||
_serial_gps->write("$CFGSYS,h15\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_UBLOX) {
|
||||
/*
|
||||
uint8_t buffer[768] = {0};
|
||||
byte _message_GNSS[8] = {0xb5, 0x62, // Sync message for UBX protocol
|
||||
0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS)
|
||||
0x00, 0x00, // Length of payload (28 bytes)
|
||||
0x00, 0x00};
|
||||
UBXChecksum(_message_GNSS, sizeof(_message_GNSS));
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_GNSS, sizeof(_message_GNSS));
|
||||
int ackLen = getACK(buffer, sizeof(buffer), 0x06, 0x3e, 2000);
|
||||
LOG_DEBUG("monver reply size = %d\n", ackLen);
|
||||
LOG_DEBUG("Ack: ");
|
||||
for (int i = 0; i < ackLen; i++) {
|
||||
LOG_DEBUG("%02X", buffer[i]);
|
||||
}
|
||||
LOG_DEBUG("\n"); */
|
||||
|
||||
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
|
||||
// We need set it because by default it is GPS only, and we want to use GLONASS too
|
||||
// Also we need SBAS for better accuracy and extra features
|
||||
// ToDo: Dynamic configure GNSS systems depending of LoRa region
|
||||
byte _message_GNSS[36] = {
|
||||
0xb5, 0x62, // Sync message for UBX protocol
|
||||
0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS)
|
||||
0x1c, 0x00, // Length of payload (28 bytes)
|
||||
0x00, // msgVer (0 for this version)
|
||||
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
|
||||
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
|
||||
0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
|
||||
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
|
||||
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
|
||||
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01, // GLONASS
|
||||
0x00, 0x00 // Checksum (to be calculated below)
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_GNSS, sizeof(_message_GNSS));
|
||||
if (strncmp(info.hwVersion, "00040007", 8) !=
|
||||
0) { // The original ublox 6 is GPS only and doesn't support the UBX-CFG-GNSS message
|
||||
if (strncmp(info.hwVersion, "00070000", 8) == 0) { // Max7 seems to only support GPS *or* GLONASS
|
||||
LOG_DEBUG("Setting GPS+SBAS\n");
|
||||
byte _message_GNSS[28] = {
|
||||
0xb5, 0x62, // Sync message for UBX protocol
|
||||
0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS)
|
||||
0x14, 0x00, // Length of payload (28 bytes)
|
||||
0x00, // msgVer (0 for this version)
|
||||
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
|
||||
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
|
||||
0x02, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
|
||||
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
|
||||
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x01, // GPS
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, // SBAS
|
||||
0x00, 0x00 // Checksum (to be calculated below)
|
||||
};
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_GNSS, sizeof(_message_GNSS));
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_GNSS, sizeof(_message_GNSS));
|
||||
} else {
|
||||
byte _message_GNSS[36] = {
|
||||
0xb5, 0x62, // Sync message for UBX protocol
|
||||
0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS)
|
||||
0x1c, 0x00, // Length of payload (28 bytes)
|
||||
0x00, // msgVer (0 for this version)
|
||||
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
|
||||
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
|
||||
0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
|
||||
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
|
||||
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
|
||||
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01, // GLONASS
|
||||
0x00, 0x00 // Checksum (to be calculated below)
|
||||
};
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_GNSS, sizeof(_message_GNSS));
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_GNSS, sizeof(_message_GNSS));
|
||||
}
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_GNSS, sizeof(_message_GNSS));
|
||||
|
||||
if (!getACK(0x06, 0x3e)) {
|
||||
// It's not critical if the module doesn't acknowledge this configuration.
|
||||
// The module should operate adequately with its factory or previously saved settings.
|
||||
// It appears that there is a firmware bug in some GPS modules: When an attempt is made
|
||||
// to overwrite a saved state with identical values, no ACK/NAK is received, contrary to
|
||||
// what is specified in the Ublox documentation.
|
||||
// There is also a possibility that the module may be GPS-only.
|
||||
LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
|
||||
return true;
|
||||
} else {
|
||||
LOG_INFO("GNSS configured for GPS+SBAS+GLONASS. Pause for 0.75s before sending next command.\n");
|
||||
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next commands
|
||||
delay(750);
|
||||
return true;
|
||||
if (getACK(0x06, 0x3e, 800) == GNSS_RESPONSE_NAK) {
|
||||
// It's not critical if the module doesn't acknowledge this configuration.
|
||||
// The module should operate adequately with its factory or previously saved settings.
|
||||
// It appears that there is a firmware bug in some GPS modules: When an attempt is made
|
||||
// to overwrite a saved state with identical values, no ACK/NAK is received, contrary to
|
||||
// what is specified in the Ublox documentation.
|
||||
// There is also a possibility that the module may be GPS-only.
|
||||
LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
|
||||
} else {
|
||||
if (strncmp(info.hwVersion, "00070000", 8) == 0) {
|
||||
LOG_INFO("GNSS configured for GPS+SBAS. Pause for 0.75s before sending next command.\n");
|
||||
} else {
|
||||
LOG_INFO("GNSS configured for GPS+SBAS+GLONASS. Pause for 0.75s before sending next command.\n");
|
||||
}
|
||||
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next
|
||||
// commands
|
||||
delay(750);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board,
|
||||
@@ -296,9 +414,8 @@ bool GPS::setupGPS()
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_JAM, sizeof(_message_JAM));
|
||||
|
||||
if (!getACK(0x06, 0x39)) {
|
||||
if (getACK(0x06, 0x39, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable interference resistance.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Configure navigation engine expert settings:
|
||||
@@ -342,25 +459,10 @@ bool GPS::setupGPS()
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_NAVX5, sizeof(_message_NAVX5));
|
||||
|
||||
if (!getACK(0x06, 0x23)) {
|
||||
if (getACK(0x06, 0x23, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to configure extra settings.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after
|
||||
setting will not output command messages in UART1, resulting in unrecognized module information
|
||||
|
||||
// Set the UART port to output NMEA only
|
||||
byte _message_nmea[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00,
|
||||
0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xAF};
|
||||
_serial_gps->write(_message_nmea, sizeof(_message_nmea));
|
||||
if (!getACK(0x06, 0x00)) {
|
||||
LOG_WARN("Unable to enable NMEA Mode.\n");
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
// ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid
|
||||
|
||||
// Set GPS update rate to 1Hz
|
||||
@@ -383,9 +485,8 @@ bool GPS::setupGPS()
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_1Hz, sizeof(_message_1Hz));
|
||||
|
||||
if (!getACK(0x06, 0x08)) {
|
||||
if (getACK(0x06, 0x08, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to set GPS update rate.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical
|
||||
@@ -407,9 +508,8 @@ bool GPS::setupGPS()
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
|
||||
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to disable NMEA GGL.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
|
||||
@@ -426,9 +526,8 @@ bool GPS::setupGPS()
|
||||
};
|
||||
UBXChecksum(_message_GSA, sizeof(_message_GSA));
|
||||
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to Enable NMEA GSA.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
|
||||
@@ -444,9 +543,8 @@ bool GPS::setupGPS()
|
||||
};
|
||||
UBXChecksum(_message_GSV, sizeof(_message_GSV));
|
||||
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to disable NMEA GSV.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
|
||||
@@ -463,9 +561,8 @@ bool GPS::setupGPS()
|
||||
};
|
||||
UBXChecksum(_message_VTG, sizeof(_message_VTG));
|
||||
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to disable NMEA VTG.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
|
||||
@@ -481,9 +578,8 @@ bool GPS::setupGPS()
|
||||
};
|
||||
UBXChecksum(_message_RMC, sizeof(_message_RMC));
|
||||
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable NMEA RMC.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
|
||||
@@ -499,9 +595,8 @@ bool GPS::setupGPS()
|
||||
};
|
||||
UBXChecksum(_message_GGA, sizeof(_message_GGA));
|
||||
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable NMEA GGA.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// The Power Management configuration allows the GPS module to operate in different power modes for optimized power
|
||||
@@ -517,27 +612,28 @@ bool GPS::setupGPS()
|
||||
// set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase and
|
||||
// must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise, it must
|
||||
// be set to '0'.
|
||||
byte UBX_CFG_PMS[14] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x86, // Message class and ID (UBX-CFG-PMS)
|
||||
0x06, 0x00, // Length of payload (6 bytes)
|
||||
0x00, // Version (0)
|
||||
0x03, // Power setup value
|
||||
0x00, 0x00, // period: not applicable, set to 0
|
||||
0x00, 0x00, // onTime: not applicable, set to 0
|
||||
0x00, 0x00 // Placeholder for checksum, will be calculated next
|
||||
};
|
||||
if (uBloxProtocolVersion >= 18) {
|
||||
byte UBX_CFG_PMS[16] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x86, // Message class and ID (UBX-CFG-PMS)
|
||||
0x08, 0x00, // Length of payload (6 bytes)
|
||||
0x00, // Version (0)
|
||||
0x03, // Power setup value
|
||||
0x00, 0x00, // period: not applicable, set to 0
|
||||
0x00, 0x00, // onTime: not applicable, set to 0
|
||||
0x97, 0x6F, // reserved, generated by u-center
|
||||
0x00, 0x00 // Placeholder for checksum, will be calculated next
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message
|
||||
UBXChecksum(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||
// Calculate the checksum and update the message
|
||||
UBXChecksum(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||
if (!getACK(0x06, 0x86)) {
|
||||
LOG_WARN("Unable to enable powersaving for GPS.\n");
|
||||
return true;
|
||||
// Send the message to the module
|
||||
_serial_gps->write(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||
if (getACK(0x06, 0x86, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to enable powersaving for GPS.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// We need save configuration to flash to make our config changes persistent
|
||||
byte _message_SAVE[21] = {
|
||||
0xB5, 0x62, // UBX protocol header
|
||||
@@ -556,12 +652,10 @@ bool GPS::setupGPS()
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_SAVE, sizeof(_message_SAVE));
|
||||
|
||||
if (!getACK(0x06, 0x09)) {
|
||||
if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("Unable to save GNSS module configuration.\n");
|
||||
return true;
|
||||
} else {
|
||||
LOG_INFO("GNSS module configuration saved!\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -675,6 +769,7 @@ void GPS::setAwake(bool on)
|
||||
if (isAwake != on) {
|
||||
LOG_DEBUG("WANT GPS=%d\n", on);
|
||||
if (on) {
|
||||
clearBuffer(); // drop any old data waiting in the buffer
|
||||
lastWakeStartMsec = millis();
|
||||
wake();
|
||||
} else {
|
||||
@@ -805,15 +900,6 @@ int32_t GPS::runOnce()
|
||||
|
||||
// If state has changed do a publish
|
||||
publishUpdate();
|
||||
|
||||
if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) {
|
||||
fixeddelayCtr++;
|
||||
// LOG_DEBUG("Our delay counter is %d\n", fixeddelayCtr);
|
||||
if (fixeddelayCtr >= 20) {
|
||||
doGPSpowersave(false);
|
||||
forceWake(false);
|
||||
}
|
||||
}
|
||||
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
|
||||
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
|
||||
return isAwake ? GPS_THREAD_INTERVAL : 5000;
|
||||
@@ -834,6 +920,14 @@ void GPS::forceWake(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
// clear the GPS rx buffer as quickly as possible
|
||||
void GPS::clearBuffer()
|
||||
{
|
||||
int x = _serial_gps->available();
|
||||
while (x--)
|
||||
_serial_gps->read();
|
||||
}
|
||||
|
||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||
int GPS::prepareSleep(void *unused)
|
||||
{
|
||||
@@ -855,50 +949,72 @@ int GPS::prepareDeepSleep(void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
GnssModel_t GPS::probe()
|
||||
GnssModel_t GPS::probe(int serialSpeed)
|
||||
{
|
||||
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
|
||||
// return immediately if the model is set by the variant.h file
|
||||
//#ifdef GPS_UBLOX (unless it's a ublox, because we might want to know the module info!
|
||||
// return GNSS_MODEL_UBLOX; think about removing this macro and return)
|
||||
#if defined(GPS_L76K)
|
||||
return GNSS_MODEL_MTK;
|
||||
#elif defined(GPS_UC6580)
|
||||
_serial_gps->updateBaudRate(115200);
|
||||
return GNSS_MODEL_UC6850;
|
||||
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040)
|
||||
_serial_gps->end();
|
||||
_serial_gps->begin(serialSpeed);
|
||||
#else
|
||||
uint8_t buffer[384] = {0};
|
||||
if (_serial_gps->baudRate() != serialSpeed) {
|
||||
LOG_DEBUG("Setting Baud to %i\n", serialSpeed);
|
||||
_serial_gps->updateBaudRate(serialSpeed);
|
||||
}
|
||||
#endif
|
||||
#ifdef GPS_DEBUG
|
||||
for (int i = 0; i < 20; i++) {
|
||||
getACK("$GP", 200);
|
||||
}
|
||||
#endif
|
||||
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
|
||||
uint8_t buffer[768] = {0};
|
||||
delay(100);
|
||||
|
||||
// Close all NMEA sentences , Only valid for MTK platform
|
||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||
delay(20);
|
||||
|
||||
// Get version information
|
||||
clearBuffer();
|
||||
_serial_gps->write("$PCAS06,0*1B\r\n");
|
||||
uint32_t startTimeout = millis() + 500;
|
||||
while (millis() < startTimeout) {
|
||||
if (_serial_gps->available()) {
|
||||
String ver = _serial_gps->readStringUntil('\r');
|
||||
// Get module info , If the correct header is returned,
|
||||
// it can be determined that it is the MTK chip
|
||||
int index = ver.indexOf("$");
|
||||
if (index != -1) {
|
||||
ver = ver.substring(index);
|
||||
if (ver.startsWith("$GPTXT,01,01,02")) {
|
||||
LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n");
|
||||
return GNSS_MODEL_MTK;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getACK("$GPTXT,01,01,02,SW=", 500) == GNSS_RESPONSE_OK) {
|
||||
LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n");
|
||||
return GNSS_MODEL_MTK;
|
||||
}
|
||||
|
||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
|
||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||
UBXChecksum(cfg_rate, sizeof(cfg_rate));
|
||||
clearBuffer();
|
||||
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
|
||||
// Check that the returned response class and message ID are correct
|
||||
if (!getAck(buffer, 384, 0x06, 0x08)) {
|
||||
LOG_WARN("Failed to find UBlox & MTK GNSS Module\n");
|
||||
GPS_RESPONSE response = getACK(0x06, 0x08, 750);
|
||||
if (response == GNSS_RESPONSE_NONE) {
|
||||
LOG_WARN("Failed to find UBlox & MTK GNSS Module using baudrate %d\n", serialSpeed);
|
||||
return GNSS_MODEL_UNKNOWN;
|
||||
} else if (response == GNSS_RESPONSE_FRAME_ERRORS) {
|
||||
LOG_INFO("UBlox Frame Errors using baudrate %d\n", serialSpeed);
|
||||
} else if (response == GNSS_RESPONSE_OK) {
|
||||
LOG_INFO("Found a UBlox Module using baudrate %d\n", serialSpeed);
|
||||
}
|
||||
|
||||
// tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after
|
||||
// setting will not output command messages in UART1, resulting in unrecognized module information
|
||||
if (serialSpeed != 9600) {
|
||||
// Set the UART port to 9600
|
||||
byte _message_prt[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00,
|
||||
0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
UBXChecksum(_message_prt, sizeof(_message_prt));
|
||||
_serial_gps->write(_message_prt, sizeof(_message_prt));
|
||||
delay(500);
|
||||
serialSpeed = 9600;
|
||||
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040)
|
||||
_serial_gps->end();
|
||||
_serial_gps->begin(serialSpeed);
|
||||
#else
|
||||
_serial_gps->updateBaudRate(serialSpeed);
|
||||
#endif
|
||||
delay(200);
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
byte _message_MONVER[8] = {
|
||||
0xB5, 0x62, // Sync message for UBX protocol
|
||||
@@ -908,9 +1024,10 @@ GnssModel_t GPS::probe()
|
||||
};
|
||||
// Get Ublox gnss module hardware and software info
|
||||
UBXChecksum(_message_MONVER, sizeof(_message_MONVER));
|
||||
clearBuffer();
|
||||
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER));
|
||||
|
||||
uint16_t len = getAck(buffer, 384, 0x0A, 0x04);
|
||||
uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200);
|
||||
if (len) {
|
||||
// LOG_DEBUG("monver reply size = %d\n", len);
|
||||
uint16_t position = 0;
|
||||
@@ -919,13 +1036,13 @@ GnssModel_t GPS::probe()
|
||||
position++;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
info.hwVersion[i] = buffer[position - 1];
|
||||
info.hwVersion[i] = buffer[position];
|
||||
position++;
|
||||
}
|
||||
|
||||
while (len >= position + 30) {
|
||||
for (int i = 0; i < 30; i++) {
|
||||
info.extension[info.extensionNo][i] = buffer[position - 1];
|
||||
info.extension[info.extensionNo][i] = buffer[position];
|
||||
position++;
|
||||
}
|
||||
info.extensionNo++;
|
||||
@@ -935,7 +1052,6 @@ GnssModel_t GPS::probe()
|
||||
|
||||
LOG_DEBUG("Module Info : \n");
|
||||
LOG_DEBUG("Soft version: %s\n", info.swVersion);
|
||||
LOG_DEBUG("first char is %c\n", (char)info.swVersion[0]);
|
||||
LOG_DEBUG("Hard version: %s\n", info.hwVersion);
|
||||
LOG_DEBUG("Extensions:%d\n", info.extensionNo);
|
||||
for (int i = 0; i < info.extensionNo; i++) {
|
||||
@@ -954,7 +1070,7 @@ GnssModel_t GPS::probe()
|
||||
} else {
|
||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
|
||||
}
|
||||
} else if (!strncmp(info.extension[i], "PROTVER=", 8)) {
|
||||
} else if (!strncmp(info.extension[i], "PROTVER", 7)) {
|
||||
char *ptr = nullptr;
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
strncpy((char *)buffer, &(info.extension[i][8]), sizeof(buffer));
|
||||
@@ -970,7 +1086,6 @@ GnssModel_t GPS::probe()
|
||||
}
|
||||
|
||||
return GNSS_MODEL_UBLOX;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_GPS
|
||||
|
||||
@@ -18,6 +18,13 @@ typedef enum {
|
||||
GNSS_MODEL_UNKNOWN,
|
||||
} GnssModel_t;
|
||||
|
||||
typedef enum {
|
||||
GNSS_RESPONSE_NONE,
|
||||
GNSS_RESPONSE_NAK,
|
||||
GNSS_RESPONSE_FRAME_ERRORS,
|
||||
GNSS_RESPONSE_OK,
|
||||
} GPS_RESPONSE;
|
||||
|
||||
// Generate a string representation of DOP
|
||||
const char *getDOPString(uint32_t dop);
|
||||
|
||||
@@ -91,6 +98,9 @@ class GPS : private concurrency::OSThread
|
||||
// Some GPS modules (ublock) require factory reset
|
||||
virtual bool factoryReset() { return true; }
|
||||
|
||||
// Empty the input buffer as quickly as possible
|
||||
void clearBuffer();
|
||||
|
||||
protected:
|
||||
/// Do gps chipset specific init, return true for success
|
||||
virtual bool setupGPS();
|
||||
@@ -158,8 +168,6 @@ class GPS : private concurrency::OSThread
|
||||
*/
|
||||
uint32_t getSleepTime() const;
|
||||
|
||||
bool getACK(uint8_t c, uint8_t i);
|
||||
|
||||
/**
|
||||
* Tell users we have new GPS readings
|
||||
*/
|
||||
@@ -169,10 +177,11 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
// Get GNSS model
|
||||
String getNMEA();
|
||||
GnssModel_t probe();
|
||||
|
||||
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
|
||||
GnssModel_t probe(int serialSpeed);
|
||||
|
||||
int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis);
|
||||
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
|
||||
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
|
||||
// delay counter to allow more sats before fixed position stops GPS thread
|
||||
uint8_t fixeddelayCtr = 0;
|
||||
|
||||
|
||||
@@ -107,6 +107,14 @@ bool NMEAGPS::lookForLocation()
|
||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||
fixQual = reader.fixQuality();
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_STATISTICS
|
||||
if (reader.failedChecksum() > lastChecksumFailCount) {
|
||||
LOG_WARN("Warning, %u new GPS checksum failures, for a total of %u.\n", reader.failedChecksum() - lastChecksumFailCount,
|
||||
reader.failedChecksum());
|
||||
lastChecksumFailCount = reader.failedChecksum();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
fixType = atoi(gsafixtype.value()); // will set to zero if no data
|
||||
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||
@@ -174,8 +182,10 @@ bool NMEAGPS::lookForLocation()
|
||||
#endif
|
||||
|
||||
// Discard incomplete or erroneous readings
|
||||
if (reader.hdop.value() == 0)
|
||||
if (reader.hdop.value() == 0) {
|
||||
LOG_WARN("BOGUS hdop.value() REJECTED: %d\n", reader.hdop.value());
|
||||
return false;
|
||||
}
|
||||
|
||||
p.latitude_i = toDegInt(loc.lat);
|
||||
p.longitude_i = toDegInt(loc.lng);
|
||||
@@ -243,7 +253,14 @@ bool NMEAGPS::hasFlow()
|
||||
bool NMEAGPS::whileIdle()
|
||||
{
|
||||
bool isValid = false;
|
||||
|
||||
#ifdef SERIAL_BUFFER_SIZE
|
||||
if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) {
|
||||
LOG_WARN("GPS Buffer full with %u bytes waiting. Flushing to avoid corruption.\n", _serial_gps->available());
|
||||
clearBuffer();
|
||||
}
|
||||
#endif
|
||||
// if (_serial_gps->available() > 0)
|
||||
// LOG_DEBUG("GPS Bytes Waiting: %u\n", _serial_gps->available());
|
||||
// First consume any chars that have piled up at the receiver
|
||||
while (_serial_gps->available() > 0) {
|
||||
int c = _serial_gps->read();
|
||||
@@ -252,4 +269,4 @@ bool NMEAGPS::whileIdle()
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ class NMEAGPS : public GPS
|
||||
{
|
||||
TinyGPSPlus reader;
|
||||
uint8_t fixQual = 0; // fix quality from GPGGA
|
||||
uint32_t lastChecksumFailCount = 0;
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
|
||||
@@ -53,4 +54,4 @@ class NMEAGPS : public GPS
|
||||
virtual bool hasLock() override;
|
||||
|
||||
virtual bool hasFlow() override;
|
||||
};
|
||||
};
|
||||
@@ -17,6 +17,10 @@ static uint32_t
|
||||
timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
|
||||
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
|
||||
|
||||
/**
|
||||
* Reads the current date and time from the RTC module and updates the system time.
|
||||
* @return True if the RTC was successfully read and the system time was updated, false otherwise.
|
||||
*/
|
||||
void readFromRTC()
|
||||
{
|
||||
struct timeval tv; /* btw settimeofday() is helpful here too*/
|
||||
@@ -83,7 +87,15 @@ void readFromRTC()
|
||||
#endif
|
||||
}
|
||||
|
||||
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
/**
|
||||
* Sets the RTC (Real-Time Clock) if the provided time is of higher quality than the current RTC time.
|
||||
*
|
||||
* @param q The quality of the provided time.
|
||||
* @param tv A pointer to a timeval struct containing the time to potentially set the RTC to.
|
||||
* @return True if the RTC was set, false otherwise.
|
||||
*
|
||||
* If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
*/
|
||||
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
{
|
||||
static uint32_t lastSetMsec = 0;
|
||||
@@ -151,6 +163,13 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the RTC time if the provided time is of higher quality than the current RTC time.
|
||||
*
|
||||
* @param q The quality of the provided time.
|
||||
* @param t The time to potentially set the RTC to.
|
||||
* @return True if the RTC was set to the provided time, false otherwise.
|
||||
*/
|
||||
bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
{
|
||||
/* Convert to unix time
|
||||
@@ -171,11 +190,22 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in seconds since the Unix epoch (January 1, 1970).
|
||||
*
|
||||
* @return The current time in seconds since the Unix epoch.
|
||||
*/
|
||||
uint32_t getTime()
|
||||
{
|
||||
return (((uint32_t)millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time from the RTC if the quality of the time is at least minQuality.
|
||||
*
|
||||
* @param minQuality The minimum quality of the RTC time required for it to be considered valid.
|
||||
* @return The current time from the RTC if it meets the minimum quality requirement, or 0 if the time is not valid.
|
||||
*/
|
||||
uint32_t getValidTime(RTCQuality minQuality)
|
||||
{
|
||||
return (currentQuality >= minQuality) ? getTime() : 0;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
/**
|
||||
* An adapter class that allows using the TFT_eSPI library as if it was an OLEDDisplay implementation.
|
||||
* An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation.
|
||||
*
|
||||
* Remaining TODO:
|
||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||
|
||||
@@ -31,15 +31,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/images.h"
|
||||
#include "input/TouchScreenImpl1.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/Channels.h"
|
||||
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
||||
#include "meshUtils.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
@@ -102,7 +103,8 @@ static uint16_t displayWidth, displayHeight;
|
||||
#define SCREEN_WIDTH displayWidth
|
||||
#define SCREEN_HEIGHT displayHeight
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
||||
@@ -363,7 +365,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
||||
{
|
||||
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled;
|
||||
return packet->from != 0 && !moduleConfig.store_forward.enabled;
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
@@ -372,7 +374,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
// the max length of this buffer is much longer than we can possibly print
|
||||
static char tempBuf[237];
|
||||
|
||||
meshtastic_MeshPacket &mp = devicestate.rx_text_message;
|
||||
const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
|
||||
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
|
||||
// mp.decoded.variant.data.decoded.bytes);
|
||||
@@ -488,11 +490,12 @@ static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *img
|
||||
}
|
||||
|
||||
// Draw nodes status
|
||||
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *nodeStatus)
|
||||
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const NodeStatus *nodeStatus)
|
||||
{
|
||||
char usersString[20];
|
||||
snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x, y + 3, 8, 8, imgUser);
|
||||
#else
|
||||
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||
@@ -835,7 +838,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
}
|
||||
|
||||
static char distStr[20];
|
||||
strncpy(distStr, "? km", sizeof(distStr)); // might not have location data
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
strncpy(distStr, "? mi", sizeof(distStr)); // might not have location data
|
||||
} else {
|
||||
strncpy(distStr, "? km", sizeof(distStr));
|
||||
}
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
int16_t compassX = 0, compassY = 0;
|
||||
@@ -851,14 +858,14 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
bool hasNodeHeading = false;
|
||||
|
||||
if (ourNode && hasValidPosition(ourNode)) {
|
||||
meshtastic_PositionLite &op = ourNode->position;
|
||||
const meshtastic_PositionLite &op = ourNode->position;
|
||||
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
|
||||
if (hasValidPosition(node)) {
|
||||
// display direction toward node
|
||||
hasNodeHeading = true;
|
||||
meshtastic_PositionLite &p = node->position;
|
||||
const meshtastic_PositionLite &p = node->position;
|
||||
float d =
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
|
||||
@@ -1040,12 +1047,19 @@ void Screen::setup()
|
||||
#endif
|
||||
serialSinceMsec = millis();
|
||||
|
||||
#if HAS_TOUCHSCREEN
|
||||
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
|
||||
touchScreenImpl1->init();
|
||||
#endif
|
||||
|
||||
// Subscribe to status updates
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
if (textMessageModule)
|
||||
textMessageObserver.observe(textMessageModule);
|
||||
if (inputBroker)
|
||||
inputObserver.observe(inputBroker);
|
||||
|
||||
// Modules can notify screen about refresh
|
||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||
@@ -1123,6 +1137,12 @@ int32_t Screen::runOnce()
|
||||
handleOnPress();
|
||||
}
|
||||
break;
|
||||
case Cmd::SHOW_PREV_FRAME:
|
||||
handleShowPrevFrame();
|
||||
break;
|
||||
case Cmd::SHOW_NEXT_FRAME:
|
||||
handleShowNextFrame();
|
||||
break;
|
||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||
break;
|
||||
@@ -1416,6 +1436,28 @@ void Screen::handleOnPress()
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::handleShowPrevFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise go back to previous frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.previousFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::handleShowNextFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise advance to next frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SCREEN_TRANSITION_FRAMERATE
|
||||
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
|
||||
#endif
|
||||
@@ -1488,7 +1530,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
#ifdef ARCH_ESP32
|
||||
if (millis() - storeForwardModule->lastHeartbeat >
|
||||
(storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgQuestionL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
@@ -1498,7 +1541,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
imgQuestion);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
|
||||
imgSFL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8,
|
||||
@@ -1510,7 +1554,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgInfoL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
@@ -1853,6 +1898,20 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Screen::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
if (showingNormalScreen && moduleFrames.size() == 0) {
|
||||
// LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
showPrevFrame();
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
showNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#else
|
||||
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||
|
||||
@@ -53,6 +53,7 @@ class Screen
|
||||
#include "commands.h"
|
||||
#include "concurrency/LockGuard.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "mesh/MeshModule.h"
|
||||
#include "power.h"
|
||||
#include <string>
|
||||
@@ -118,6 +119,8 @@ class Screen : public concurrency::OSThread
|
||||
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
|
||||
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
||||
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
|
||||
CallbackObserver<Screen, const InputEvent *> inputObserver =
|
||||
CallbackObserver<Screen, const InputEvent *>(this, &Screen::handleInputEvent);
|
||||
|
||||
public:
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
@@ -152,8 +155,10 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
void blink();
|
||||
|
||||
/// Handles a button press.
|
||||
/// Handle button press, trackball or swipe action)
|
||||
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
|
||||
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
|
||||
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
|
||||
|
||||
// Implementation to Adjust Brightness
|
||||
void adjustBrightness();
|
||||
@@ -301,9 +306,11 @@ class Screen : public concurrency::OSThread
|
||||
// Use this handle to set things like battery status, user count, GPS status, etc.
|
||||
DebugInfo *debug_info() { return &debugInfo; }
|
||||
|
||||
// Handle observer events
|
||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||
int handleTextMessage(const meshtastic_MeshPacket *arg);
|
||||
int handleUIFrameEvent(const UIFrameEvent *arg);
|
||||
int handleInputEvent(const InputEvent *arg);
|
||||
|
||||
/// Used to force (super slow) eink displays to draw critical frames
|
||||
void forceDisplay();
|
||||
@@ -313,13 +320,6 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
void setWelcomeFrames();
|
||||
|
||||
void getTouch(int *x, int *y)
|
||||
{
|
||||
#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
dispdev.getTouch(x, y);
|
||||
#endif
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Updates the UI.
|
||||
//
|
||||
@@ -350,6 +350,8 @@ class Screen : public concurrency::OSThread
|
||||
// Implementations of various commands, called from doTask().
|
||||
void handleSetOn(bool on);
|
||||
void handleOnPress();
|
||||
void handleShowNextFrame();
|
||||
void handleShowPrevFrame();
|
||||
void handleStartBluetoothPinScreen(uint32_t pin);
|
||||
void handlePrint(const char *text);
|
||||
void handleStartFirmwareUpdateScreen();
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#define TFT_BACKLIGHT_ON HIGH
|
||||
#endif
|
||||
|
||||
// convert 24-bit color to 16-bit (56K)
|
||||
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
|
||||
#ifndef TFT_MESH
|
||||
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
|
||||
#endif
|
||||
|
||||
#if defined(ST7735S)
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
@@ -108,10 +108,12 @@ class LGFX : public lgfx::LGFX_Device
|
||||
lgfx::Panel_ST7789 _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
#if HAS_TOUCHSCREEN
|
||||
#ifdef T_WATCH_S3
|
||||
lgfx::Touch_FT5x06 _touch_instance;
|
||||
#else
|
||||
lgfx::Touch_GT911 _touch_instance;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -126,13 +128,14 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
cfg.pin_sclk = ST7789_SCK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = ST7789_SDA; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = ST7789_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = ST7789_RS; // Set SPI DC pin number (-1 = disable)
|
||||
cfg.spi_3wire = false;
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
// SPI_DMA_CH_AUTO=auto setting)
|
||||
cfg.pin_sclk = ST7789_SCK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = ST7789_SDA; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = ST7789_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = ST7789_RS; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||
@@ -148,16 +151,16 @@ class LGFX : public lgfx::LGFX_Device
|
||||
// The following setting values are general initial values for each panel, so please comment out any
|
||||
// unknown items and try them.
|
||||
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = TFT_OFFSET_ROTATION; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit =
|
||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
@@ -174,13 +177,14 @@ class LGFX : public lgfx::LGFX_Device
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
cfg.pin_bl = ST7789_BL; // Pin number to which the backlight is connected
|
||||
cfg.invert = true; // true to invert the brightness of the backlight
|
||||
cfg.invert = false; // true to invert the brightness of the backlight
|
||||
// cfg.pwm_channel = 0;
|
||||
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||
}
|
||||
|
||||
#if HAS_TOUCHSCREEN
|
||||
// Configure settings for touch screen control.
|
||||
{
|
||||
auto cfg = _touch_instance.config();
|
||||
@@ -192,11 +196,11 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.y_max = TFT_WIDTH - 1;
|
||||
cfg.pin_int = SCREEN_TOUCH_INT;
|
||||
cfg.bus_shared = true;
|
||||
cfg.offset_rotation = 0;
|
||||
cfg.offset_rotation = TFT_OFFSET_ROTATION;
|
||||
// cfg.freq = 2500000;
|
||||
|
||||
// I2C
|
||||
cfg.i2c_port = 1;
|
||||
cfg.i2c_port = TOUCH_I2C_PORT;
|
||||
cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
|
||||
#ifdef SCREEN_TOUCH_USE_I2C1
|
||||
cfg.pin_sda = I2C_SDA1;
|
||||
@@ -205,11 +209,12 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.pin_sda = I2C_SDA;
|
||||
cfg.pin_scl = I2C_SCL;
|
||||
#endif
|
||||
cfg.freq = 400000;
|
||||
// cfg.freq = 400000;
|
||||
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
setPanel(&_panel_instance); // Sets the panel to use.
|
||||
}
|
||||
@@ -217,7 +222,96 @@ class LGFX : public lgfx::LGFX_Device
|
||||
|
||||
static LGFX tft;
|
||||
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
||||
#elif defined(ILI9341_DRIVER)
|
||||
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341 driver chip
|
||||
|
||||
#if defined(ILI9341_BACKLIGHT_EN) && !defined(TFT_BL)
|
||||
#define TFT_BL ILI9341_BACKLIGHT_EN
|
||||
#endif
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_ILI9341 _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
|
||||
public:
|
||||
LGFX(void)
|
||||
{
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
|
||||
// configure SPI
|
||||
cfg.spi_host = ILI9341_SPI_HOST; // ESP32-S2,S3,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
|
||||
cfg.spi_mode = 0;
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
// SPI_DMA_CH_AUTO=auto setting)
|
||||
cfg.pin_sclk = TFT_SCLK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = TFT_MOSI; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = TFT_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = TFT_DC; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||
}
|
||||
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = TFT_CS; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = TFT_RST; // Pin number where RST is connected (-1 = disable)
|
||||
cfg.pin_busy = TFT_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||
|
||||
// The following setting values are general initial values for each panel, so please comment out any
|
||||
// unknown items and try them.
|
||||
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is upside down)
|
||||
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = false; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit =
|
||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
|
||||
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||
// ST7735 or ILI9163.
|
||||
cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||
cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
|
||||
// Set the backlight control
|
||||
{
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
cfg.pin_bl = TFT_BL; // Pin number to which the backlight is connected
|
||||
cfg.invert = false; // true to invert the brightness of the backlight
|
||||
// cfg.freq = 44100; // PWM frequency of backlight
|
||||
// cfg.pwm_channel = 1; // PWM channel number to use
|
||||
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||
}
|
||||
|
||||
setPanel(&_panel_instance);
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX tft;
|
||||
|
||||
#elif defined(ST7735_CS)
|
||||
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
||||
|
||||
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
||||
@@ -275,6 +369,9 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
#endif
|
||||
#ifndef M5STACK
|
||||
tft.setBrightness(128);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -284,6 +381,9 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, HIGH);
|
||||
#endif
|
||||
#ifndef M5STACK
|
||||
tft.setBrightness(0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -294,6 +394,32 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
// Drop all other commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
void TFTDisplay::flipScreenVertically()
|
||||
{
|
||||
#if defined(T_WATCH_S3)
|
||||
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
|
||||
tft.setRotation(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TFTDisplay::hasTouch(void)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
return tft.touch() != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
return tft.getTouch(x, y);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TFTDisplay::setDetected(uint8_t detected)
|
||||
{
|
||||
(void)detected;
|
||||
@@ -311,10 +437,12 @@ bool TFTDisplay::connect()
|
||||
#endif
|
||||
|
||||
tft.init();
|
||||
#if defined(M5STACK) || defined(T_DECK)
|
||||
tft.setRotation(1); // M5Stack/T-Deck have the TFT in landscape
|
||||
#if defined(M5STACK)
|
||||
tft.setRotation(0);
|
||||
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
|
||||
tft.setRotation(1); // T-Deck has the TFT in landscape
|
||||
#elif defined(T_WATCH_S3)
|
||||
tft.setRotation(0); // T-Watch S3 has the TFT in portrait
|
||||
tft.setRotation(2); // T-Watch S3 left-handed orientation
|
||||
#else
|
||||
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||
#endif
|
||||
@@ -322,12 +450,4 @@ bool TFTDisplay::connect()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get touch coords from the display
|
||||
void TFTDisplay::getTouch(int *x, int *y)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
tft.getTouch(x, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
/**
|
||||
* An adapter class that allows using the TFT_eSPI library as if it was an OLEDDisplay implementation.
|
||||
* An adapter class that allows using the LovyanGFX library as if it was an OLEDDisplay implementation.
|
||||
*
|
||||
* Remaining TODO:
|
||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||
@@ -22,14 +22,19 @@ class TFTDisplay : public OLEDDisplay
|
||||
// Write the buffer to the display memory
|
||||
virtual void display(void) override;
|
||||
|
||||
// Turn the display upside down
|
||||
virtual void flipScreenVertically();
|
||||
|
||||
// Touch screen (static handlers)
|
||||
static bool hasTouch(void);
|
||||
static bool getTouch(int16_t *x, int16_t *y);
|
||||
|
||||
/**
|
||||
* shim to make the abstraction happy
|
||||
*
|
||||
*/
|
||||
void setDetected(uint8_t detected);
|
||||
|
||||
void getTouch(int *x, int *y);
|
||||
|
||||
protected:
|
||||
// the header size of the buffer used, e.g. for the SPI command header
|
||||
virtual int getBufferOffset(void) override { return 0; }
|
||||
|
||||
@@ -14,7 +14,8 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
|
||||
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
|
||||
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||
const uint8_t imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff};
|
||||
|
||||
181
src/input/BBQ10Keyboard.cpp
Normal file
181
src/input/BBQ10Keyboard.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "BBQ10Keyboard.h"
|
||||
|
||||
#define _REG_VER 1
|
||||
#define _REG_CFG 2
|
||||
#define _REG_INT 3
|
||||
#define _REG_KEY 4
|
||||
#define _REG_BKL 5
|
||||
#define _REG_DEB 6
|
||||
#define _REG_FRQ 7
|
||||
#define _REG_RST 8
|
||||
#define _REG_FIF 9
|
||||
|
||||
#define _WRITE_MASK (1 << 7)
|
||||
|
||||
#define CFG_OVERFLOW_ON (1 << 0)
|
||||
#define CFG_OVERFLOW_INT (1 << 1)
|
||||
#define CFG_CAPSLOCK_INT (1 << 2)
|
||||
#define CFG_NUMLOCK_INT (1 << 3)
|
||||
#define CFG_KEY_INT (1 << 4)
|
||||
#define CFG_PANIC_INT (1 << 5)
|
||||
#define CFG_REPORT_MODS (1 << 6)
|
||||
#define CFG_USE_MODS (1 << 7)
|
||||
|
||||
#define INT_OVERFLOW (1 << 0)
|
||||
#define INT_CAPSLOCK (1 << 1)
|
||||
#define INT_NUMLOCK (1 << 2)
|
||||
#define INT_KEY (1 << 3)
|
||||
#define INT_PANIC (1 << 4)
|
||||
|
||||
#define KEY_CAPSLOCK (1 << 5)
|
||||
#define KEY_NUMLOCK (1 << 6)
|
||||
#define KEY_COUNT_MASK (0x1F)
|
||||
|
||||
BBQ10Keyboard::BBQ10Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr) {}
|
||||
|
||||
void BBQ10Keyboard::begin(uint8_t addr, TwoWire *wire)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = wire;
|
||||
|
||||
m_wire->begin();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = nullptr;
|
||||
writeCallback = w;
|
||||
readCallback = r;
|
||||
reset();
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::reset()
|
||||
{
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(_REG_RST);
|
||||
m_wire->endTransmission();
|
||||
}
|
||||
if (writeCallback) {
|
||||
uint8_t data = 0;
|
||||
writeCallback(m_addr, _REG_RST, &data, 0);
|
||||
}
|
||||
delay(100);
|
||||
writeRegister(_REG_CFG, readRegister8(_REG_CFG) | CFG_REPORT_MODS);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
|
||||
{
|
||||
pinMode(pin, INPUT_PULLUP);
|
||||
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::detachInterrupt(uint8_t pin) const
|
||||
{
|
||||
::detachInterrupt(pin);
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::clearInterruptStatus()
|
||||
{
|
||||
writeRegister(_REG_INT, 0x00);
|
||||
}
|
||||
|
||||
uint8_t BBQ10Keyboard::status() const
|
||||
{
|
||||
return readRegister8(_REG_KEY);
|
||||
}
|
||||
|
||||
uint8_t BBQ10Keyboard::keyCount() const
|
||||
{
|
||||
return status() & KEY_COUNT_MASK;
|
||||
}
|
||||
|
||||
BBQ10Keyboard::KeyEvent BBQ10Keyboard::keyEvent() const
|
||||
{
|
||||
KeyEvent event = {.key = '\0', .state = StateIdle};
|
||||
|
||||
if (keyCount() == 0)
|
||||
return event;
|
||||
|
||||
const uint16_t buf = readRegister16(_REG_FIF);
|
||||
event.key = buf >> 8;
|
||||
event.state = KeyState(buf & 0xFF);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
float BBQ10Keyboard::backlight() const
|
||||
{
|
||||
return readRegister8(_REG_BKL) / 255.0f;
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::setBacklight(float value)
|
||||
{
|
||||
writeRegister(_REG_BKL, value * 255);
|
||||
}
|
||||
|
||||
uint8_t BBQ10Keyboard::readRegister8(uint8_t reg) const
|
||||
{
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(reg);
|
||||
m_wire->endTransmission();
|
||||
|
||||
m_wire->requestFrom(m_addr, (uint8_t)1);
|
||||
if (m_wire->available() < 1)
|
||||
return 0;
|
||||
|
||||
return m_wire->read();
|
||||
}
|
||||
if (readCallback) {
|
||||
uint8_t data;
|
||||
readCallback(m_addr, reg, &data, 1);
|
||||
return data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t BBQ10Keyboard::readRegister16(uint8_t reg) const
|
||||
{
|
||||
uint8_t data[2] = {0};
|
||||
// uint8_t low = 0, high = 0;
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(reg);
|
||||
m_wire->endTransmission();
|
||||
|
||||
m_wire->requestFrom(m_addr, (uint8_t)2);
|
||||
if (m_wire->available() < 2)
|
||||
return 0;
|
||||
data[0] = m_wire->read();
|
||||
data[1] = m_wire->read();
|
||||
}
|
||||
if (readCallback) {
|
||||
readCallback(m_addr, reg, data, 2);
|
||||
}
|
||||
return (data[1] << 8) | data[0];
|
||||
}
|
||||
|
||||
void BBQ10Keyboard::writeRegister(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = reg | _WRITE_MASK;
|
||||
data[1] = value;
|
||||
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(data, sizeof(uint8_t) * 2);
|
||||
m_wire->endTransmission();
|
||||
}
|
||||
if (writeCallback) {
|
||||
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||
}
|
||||
}
|
||||
51
src/input/BBQ10Keyboard.h
Normal file
51
src/input/BBQ10Keyboard.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
|
||||
|
||||
#include "configuration.h"
|
||||
#include <Wire.h>
|
||||
|
||||
#define KEY_MOD_ALT (0x1A)
|
||||
#define KEY_MOD_SHL (0x1B)
|
||||
#define KEY_MOD_SHR (0x1C)
|
||||
#define KEY_MOD_SYM (0x1D)
|
||||
|
||||
class BBQ10Keyboard
|
||||
{
|
||||
public:
|
||||
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||
|
||||
enum KeyState { StateIdle = 0, StatePress, StateLongPress, StateRelease };
|
||||
|
||||
struct KeyEvent {
|
||||
char key;
|
||||
KeyState state;
|
||||
};
|
||||
|
||||
BBQ10Keyboard();
|
||||
|
||||
void begin(uint8_t addr = BBQ10_KB_ADDR, TwoWire *wire = &Wire);
|
||||
|
||||
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = BBQ10_KB_ADDR);
|
||||
|
||||
void reset(void);
|
||||
|
||||
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
|
||||
void detachInterrupt(uint8_t pin) const;
|
||||
void clearInterruptStatus(void);
|
||||
|
||||
uint8_t status(void) const;
|
||||
uint8_t keyCount(void) const;
|
||||
KeyEvent keyEvent(void) const;
|
||||
|
||||
float backlight() const;
|
||||
void setBacklight(float value);
|
||||
|
||||
uint8_t readRegister8(uint8_t reg) const;
|
||||
uint16_t readRegister16(uint8_t reg) const;
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
|
||||
private:
|
||||
TwoWire *m_wire;
|
||||
uint8_t m_addr;
|
||||
i2c_com_fptr_t readCallback;
|
||||
i2c_com_fptr_t writeCallback;
|
||||
};
|
||||
137
src/input/TouchScreenBase.cpp
Normal file
137
src/input/TouchScreenBase.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "TouchScreenBase.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifndef TIME_LONG_PRESS
|
||||
#define TIME_LONG_PRESS 400
|
||||
#endif
|
||||
|
||||
// move a minimum distance over the screen to detect a "swipe"
|
||||
#ifndef TOUCH_THRESHOLD_X
|
||||
#define TOUCH_THRESHOLD_X 30
|
||||
#endif
|
||||
|
||||
#ifndef TOUCH_THRESHOLD_Y
|
||||
#define TOUCH_THRESHOLD_Y 20
|
||||
#endif
|
||||
|
||||
TouchScreenBase::TouchScreenBase(const char *name, uint16_t width, uint16_t height)
|
||||
: concurrency::OSThread(name), _display_width(width), _display_height(height), _first_x(0), _last_x(0), _first_y(0),
|
||||
_last_y(0), _start(0), _tapped(false), _originName(name)
|
||||
{
|
||||
}
|
||||
|
||||
void TouchScreenBase::init(bool hasTouch)
|
||||
{
|
||||
if (hasTouch) {
|
||||
LOG_INFO("TouchScreen initialized %d %d\n", TOUCH_THRESHOLD_X, TOUCH_THRESHOLD_Y);
|
||||
this->setInterval(100);
|
||||
} else {
|
||||
disable();
|
||||
this->setInterval(UINT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t TouchScreenBase::runOnce()
|
||||
{
|
||||
TouchEvent e;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_NONE);
|
||||
|
||||
// process touch events
|
||||
int16_t x, y;
|
||||
bool touched = getTouch(x, y);
|
||||
if (touched) {
|
||||
this->setInterval(20);
|
||||
_last_x = x;
|
||||
_last_y = y;
|
||||
}
|
||||
if (touched != _touchedOld) {
|
||||
if (touched) {
|
||||
hapticFeedback();
|
||||
_state = TOUCH_EVENT_OCCURRED;
|
||||
_start = millis();
|
||||
_first_x = x;
|
||||
_first_y = y;
|
||||
} else {
|
||||
_state = TOUCH_EVENT_CLEARED;
|
||||
time_t duration = millis() - _start;
|
||||
x = _last_x;
|
||||
y = _last_y;
|
||||
this->setInterval(50);
|
||||
|
||||
// compute distance
|
||||
int16_t dx = x - _first_x;
|
||||
int16_t dy = y - _first_y;
|
||||
uint16_t adx = abs(dx);
|
||||
uint16_t ady = abs(dy);
|
||||
|
||||
// swipe horizontal
|
||||
if (adx > ady && adx > TOUCH_THRESHOLD_X) {
|
||||
if (0 > dx) { // swipe right to left
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_LEFT);
|
||||
LOG_DEBUG("action SWIPE: right to left\n");
|
||||
} else { // swipe left to right
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_RIGHT);
|
||||
LOG_DEBUG("action SWIPE: left to right\n");
|
||||
}
|
||||
}
|
||||
// swipe vertical
|
||||
else if (ady > adx && ady > TOUCH_THRESHOLD_Y) {
|
||||
if (0 > dy) { // swipe bottom to top
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_UP);
|
||||
LOG_DEBUG("action SWIPE: bottom to top\n");
|
||||
} else { // swipe top to bottom
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOWN);
|
||||
LOG_DEBUG("action SWIPE: top to bottom\n");
|
||||
}
|
||||
}
|
||||
// tap
|
||||
else {
|
||||
if (duration > 0 && duration < TIME_LONG_PRESS) {
|
||||
if (_tapped) {
|
||||
_tapped = false;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOUBLE_TAP);
|
||||
LOG_DEBUG("action DOUBLE TAP(%d/%d)\n", x, y);
|
||||
} else {
|
||||
_tapped = true;
|
||||
}
|
||||
} else {
|
||||
_tapped = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_touchedOld = touched;
|
||||
|
||||
// fire TAP event when no 2nd tap occured within time
|
||||
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
|
||||
_tapped = false;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
|
||||
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
|
||||
}
|
||||
|
||||
// fire LONG_PRESS event without the need for release
|
||||
if (touched && (time_t(millis()) - _start) > TIME_LONG_PRESS) {
|
||||
// tricky: prevent reoccurring events and another touch event when releasing
|
||||
_start = millis() + 30000;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_LONG_PRESS);
|
||||
LOG_DEBUG("action LONG PRESS(%d/%d)\n", _last_x, _last_y);
|
||||
}
|
||||
|
||||
if (e.touchEvent != TOUCH_ACTION_NONE) {
|
||||
e.source = this->_originName;
|
||||
e.x = _last_x;
|
||||
e.y = _last_y;
|
||||
onEvent(e);
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
void TouchScreenBase::hapticFeedback()
|
||||
{
|
||||
#ifdef T_WATCH_S3
|
||||
drv.setWaveform(0, 75);
|
||||
drv.setWaveform(1, 0); // end waveform
|
||||
drv.go();
|
||||
#endif
|
||||
}
|
||||
55
src/input/TouchScreenBase.h
Normal file
55
src/input/TouchScreenBase.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
typedef struct _TouchEvent {
|
||||
const char *source;
|
||||
char touchEvent;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
} TouchEvent;
|
||||
|
||||
class TouchScreenBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit TouchScreenBase(const char *name, uint16_t width, uint16_t height);
|
||||
void init(bool hasTouch);
|
||||
|
||||
protected:
|
||||
enum TouchScreenBaseStateType { TOUCH_EVENT_OCCURRED, TOUCH_EVENT_CLEARED };
|
||||
|
||||
enum TouchScreenBaseEventType {
|
||||
TOUCH_ACTION_NONE,
|
||||
TOUCH_ACTION_UP,
|
||||
TOUCH_ACTION_DOWN,
|
||||
TOUCH_ACTION_LEFT,
|
||||
TOUCH_ACTION_RIGHT,
|
||||
TOUCH_ACTION_TAP,
|
||||
TOUCH_ACTION_DOUBLE_TAP,
|
||||
TOUCH_ACTION_LONG_PRESS
|
||||
};
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
virtual bool getTouch(int16_t &x, int16_t &y) = 0;
|
||||
virtual void onEvent(const TouchEvent &event) = 0;
|
||||
|
||||
volatile TouchScreenBaseStateType _state = TOUCH_EVENT_CLEARED;
|
||||
volatile TouchScreenBaseEventType _action = TOUCH_ACTION_NONE;
|
||||
void hapticFeedback();
|
||||
|
||||
protected:
|
||||
uint16_t _display_width;
|
||||
uint16_t _display_height;
|
||||
|
||||
private:
|
||||
bool _touchedOld = false; // previous touch state
|
||||
int16_t _first_x, _last_x; // horizontal swipe direction
|
||||
int16_t _first_y, _last_y; // vertical swipe direction
|
||||
time_t _start; // for LONG_PRESS
|
||||
bool _tapped; // for DOUBLE_TAP
|
||||
|
||||
const char *_originName;
|
||||
};
|
||||
73
src/input/TouchScreenImpl1.cpp
Normal file
73
src/input/TouchScreenImpl1.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "TouchScreenImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TouchScreenImpl1 *touchScreenImpl1;
|
||||
|
||||
TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *))
|
||||
: TouchScreenBase("touchscreen1", width, height), _getTouch(getTouch)
|
||||
{
|
||||
}
|
||||
|
||||
void TouchScreenImpl1::init()
|
||||
{
|
||||
#if !HAS_TOUCHSCREEN
|
||||
TouchScreenBase::init(false);
|
||||
return;
|
||||
#else
|
||||
TouchScreenBase::init(true);
|
||||
inputBroker->registerSource(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TouchScreenImpl1::getTouch(int16_t &x, int16_t &y)
|
||||
{
|
||||
return _getTouch(&x, &y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief forward touchscreen event
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* The touchscreen events are translated to input events and reversed
|
||||
*/
|
||||
void TouchScreenImpl1::onEvent(const TouchEvent &event)
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = event.source;
|
||||
switch (event.touchEvent) {
|
||||
case TOUCH_ACTION_LEFT: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_RIGHT: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_UP: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_DOWN: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_DOUBLE_TAP: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_LONG_PRESS: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_TAP: {
|
||||
powerFSM.trigger(EVENT_INPUT);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
17
src/input/TouchScreenImpl1.h
Normal file
17
src/input/TouchScreenImpl1.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "TouchScreenBase.h"
|
||||
|
||||
class TouchScreenImpl1 : public TouchScreenBase
|
||||
{
|
||||
public:
|
||||
TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *));
|
||||
void init(void);
|
||||
|
||||
protected:
|
||||
virtual bool getTouch(int16_t &x, int16_t &y);
|
||||
virtual void onEvent(const TouchEvent &event);
|
||||
|
||||
bool (*_getTouch)(int16_t *, int16_t *);
|
||||
};
|
||||
|
||||
extern TouchScreenImpl1 *touchScreenImpl1;
|
||||
95
src/input/TrackballInterruptBase.cpp
Normal file
95
src/input/TrackballInterruptBase.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "TrackballInterruptBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TrackballInterruptBase::TrackballInterruptBase(const char *name) : concurrency::OSThread(name), _originName(name) {}
|
||||
|
||||
void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress,
|
||||
char eventDown, char eventUp, char eventLeft, char eventRight, char eventPressed,
|
||||
void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(),
|
||||
void (*onIntPress)())
|
||||
{
|
||||
this->_pinDown = pinDown;
|
||||
this->_pinUp = pinUp;
|
||||
this->_pinLeft = pinLeft;
|
||||
this->_pinRight = pinRight;
|
||||
this->_eventDown = eventDown;
|
||||
this->_eventUp = eventUp;
|
||||
this->_eventLeft = eventLeft;
|
||||
this->_eventRight = eventRight;
|
||||
this->_eventPressed = eventPressed;
|
||||
|
||||
pinMode(pinPress, INPUT_PULLUP);
|
||||
pinMode(this->_pinDown, INPUT_PULLUP);
|
||||
pinMode(this->_pinUp, INPUT_PULLUP);
|
||||
pinMode(this->_pinLeft, INPUT_PULLUP);
|
||||
pinMode(this->_pinRight, INPUT_PULLUP);
|
||||
|
||||
attachInterrupt(pinPress, onIntPress, RISING);
|
||||
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
||||
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
||||
attachInterrupt(this->_pinLeft, onIntLeft, RISING);
|
||||
attachInterrupt(this->_pinRight, onIntRight, RISING);
|
||||
|
||||
LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)\n", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
|
||||
pinPress);
|
||||
|
||||
this->setInterval(100);
|
||||
}
|
||||
|
||||
int32_t TrackballInterruptBase::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
|
||||
if (this->action == TB_ACTION_PRESSED) {
|
||||
// LOG_DEBUG("Trackball event Press\n");
|
||||
e.inputEvent = this->_eventPressed;
|
||||
} else if (this->action == TB_ACTION_UP) {
|
||||
// LOG_DEBUG("Trackball event UP\n");
|
||||
e.inputEvent = this->_eventUp;
|
||||
} else if (this->action == TB_ACTION_DOWN) {
|
||||
// LOG_DEBUG("Trackball event DOWN\n");
|
||||
e.inputEvent = this->_eventDown;
|
||||
} else if (this->action == TB_ACTION_LEFT) {
|
||||
// LOG_DEBUG("Trackball event LEFT\n");
|
||||
e.inputEvent = this->_eventLeft;
|
||||
} else if (this->action == TB_ACTION_RIGHT) {
|
||||
// LOG_DEBUG("Trackball event RIGHT\n");
|
||||
e.inputEvent = this->_eventRight;
|
||||
}
|
||||
|
||||
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
e.source = this->_originName;
|
||||
e.kbchar = 0x00;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
this->action = TB_ACTION_NONE;
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intPressHandler()
|
||||
{
|
||||
this->action = TB_ACTION_PRESSED;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intDownHandler()
|
||||
{
|
||||
this->action = TB_ACTION_DOWN;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intUpHandler()
|
||||
{
|
||||
this->action = TB_ACTION_UP;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intLeftHandler()
|
||||
{
|
||||
this->action = TB_ACTION_LEFT;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intRightHandler()
|
||||
{
|
||||
this->action = TB_ACTION_RIGHT;
|
||||
}
|
||||
44
src/input/TrackballInterruptBase.h
Normal file
44
src/input/TrackballInterruptBase.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
class TrackballInterruptBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit TrackballInterruptBase(const char *name);
|
||||
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress, char eventDown, char eventUp,
|
||||
char eventLeft, char eventRight, char eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(),
|
||||
void (*onIntRight)(), void (*onIntPress)());
|
||||
void intPressHandler();
|
||||
void intDownHandler();
|
||||
void intUpHandler();
|
||||
void intLeftHandler();
|
||||
void intRightHandler();
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
protected:
|
||||
enum TrackballInterruptBaseActionType {
|
||||
TB_ACTION_NONE,
|
||||
TB_ACTION_PRESSED,
|
||||
TB_ACTION_UP,
|
||||
TB_ACTION_DOWN,
|
||||
TB_ACTION_LEFT,
|
||||
TB_ACTION_RIGHT
|
||||
};
|
||||
|
||||
volatile TrackballInterruptBaseActionType action = TB_ACTION_NONE;
|
||||
|
||||
private:
|
||||
uint8_t _pinDown = 0;
|
||||
uint8_t _pinUp = 0;
|
||||
uint8_t _pinLeft = 0;
|
||||
uint8_t _pinRight = 0;
|
||||
char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventLeft = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventRight = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
const char *_originName;
|
||||
};
|
||||
54
src/input/TrackballInterruptImpl1.cpp
Normal file
54
src/input/TrackballInterruptImpl1.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "TrackballInterruptImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TrackballInterruptImpl1 *trackballInterruptImpl1;
|
||||
|
||||
TrackballInterruptImpl1::TrackballInterruptImpl1() : TrackballInterruptBase("trackball1") {}
|
||||
|
||||
void TrackballInterruptImpl1::init()
|
||||
{
|
||||
#if !HAS_TRACKBALL
|
||||
// Input device is disabled.
|
||||
return;
|
||||
#else
|
||||
uint8_t pinUp = TB_UP;
|
||||
uint8_t pinDown = TB_DOWN;
|
||||
uint8_t pinLeft = TB_LEFT;
|
||||
uint8_t pinRight = TB_RIGHT;
|
||||
uint8_t pinPress = TB_PRESS;
|
||||
|
||||
char eventDown = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
|
||||
char eventUp = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
|
||||
char eventLeft = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
|
||||
char eventRight = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
|
||||
char eventPressed = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
|
||||
|
||||
TrackballInterruptBase::init(pinDown, pinUp, pinLeft, pinRight, pinPress, eventDown, eventUp, eventLeft, eventRight,
|
||||
eventPressed, TrackballInterruptImpl1::handleIntDown, TrackballInterruptImpl1::handleIntUp,
|
||||
TrackballInterruptImpl1::handleIntLeft, TrackballInterruptImpl1::handleIntRight,
|
||||
TrackballInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackballInterruptImpl1::handleIntDown()
|
||||
{
|
||||
trackballInterruptImpl1->intDownHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntUp()
|
||||
{
|
||||
trackballInterruptImpl1->intUpHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntLeft()
|
||||
{
|
||||
trackballInterruptImpl1->intLeftHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntRight()
|
||||
{
|
||||
trackballInterruptImpl1->intRightHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
trackballInterruptImpl1->intPressHandler();
|
||||
}
|
||||
16
src/input/TrackballInterruptImpl1.h
Normal file
16
src/input/TrackballInterruptImpl1.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "TrackballInterruptBase.h"
|
||||
|
||||
class TrackballInterruptImpl1 : public TrackballInterruptBase
|
||||
{
|
||||
public:
|
||||
TrackballInterruptImpl1();
|
||||
void init();
|
||||
static void handleIntDown();
|
||||
static void handleIntUp();
|
||||
static void handleIntLeft();
|
||||
static void handleIntRight();
|
||||
static void handleIntPressed();
|
||||
};
|
||||
|
||||
extern TrackballInterruptImpl1 *trackballInterruptImpl1;
|
||||
@@ -23,7 +23,7 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
|
||||
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
||||
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
||||
|
||||
LOG_DEBUG("GPIO initialized (%d, %d, %d)\n", this->_pinDown, this->_pinUp, pinPress);
|
||||
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)\n", this->_pinUp, this->_pinDown, pinPress);
|
||||
}
|
||||
|
||||
void UpDownInterruptBase::intPressHandler()
|
||||
|
||||
@@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
|
||||
|
||||
void CardKbI2cImpl::init()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR) {
|
||||
if (cardkb_found.address == 0x00) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,20 +28,9 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len
|
||||
return readflag;
|
||||
}
|
||||
|
||||
// Unused for now - flagging it off
|
||||
#if 0
|
||||
void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
|
||||
{
|
||||
i2cBus->beginTransmission(CARDKB_ADDR);
|
||||
i2cBus->write(reg);
|
||||
i2cBus->write(data);
|
||||
i2cBus->endTransmission(); // stop transmitting
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t KbI2cBase::runOnce()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR) {
|
||||
if (cardkb_found.address == 0x00) {
|
||||
// Input device is not detected.
|
||||
return INT32_MAX;
|
||||
}
|
||||
@@ -52,11 +41,19 @@ int32_t KbI2cBase::runOnce()
|
||||
#ifdef I2C_SDA1
|
||||
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
|
||||
i2cBus = &Wire1;
|
||||
if (cardkb_found.address == BBQ10_KB_ADDR) {
|
||||
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire1);
|
||||
Q10keyboard.setBacklight(0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case ScanI2C::WIRE:
|
||||
LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
|
||||
i2cBus = &Wire;
|
||||
if (cardkb_found.address == BBQ10_KB_ADDR) {
|
||||
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire);
|
||||
Q10keyboard.setBacklight(0);
|
||||
}
|
||||
break;
|
||||
case ScanI2C::NO_I2C:
|
||||
default:
|
||||
@@ -64,7 +61,105 @@ int32_t KbI2cBase::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
if (kb_model == 0x02) {
|
||||
switch (kb_model) {
|
||||
case 0x11: { // BB Q10
|
||||
int keyCount = Q10keyboard.keyCount();
|
||||
while (keyCount--) {
|
||||
const BBQ10Keyboard::KeyEvent key = Q10keyboard.keyEvent();
|
||||
if ((key.key != 0x00) && (key.state == BBQ10Keyboard::StateRelease)) {
|
||||
InputEvent e;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
switch (key.key) {
|
||||
case 'p': // TAB
|
||||
case 't': // TAB as well
|
||||
if (is_sym) {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0x09; // TAB Scancode
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 'q': // ESC
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
e.kbchar = 0x1b;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 0x08: // Back
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||
e.kbchar = key.key;
|
||||
break;
|
||||
case 'e': // sym e
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
e.kbchar = 0xb5;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 'x': // sym x
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
e.kbchar = 0xb6;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 's': // sym s
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
e.kbchar = 0x00; // tweak for destSelect
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 'f': // sym f
|
||||
if (is_sym) {
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = 0x00; // tweak for destSelect
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 0x13: // Code scanner says the SYM key is 0x13
|
||||
is_sym = !is_sym;
|
||||
break;
|
||||
case 0x0a: // apparently Enter on Q10 is a line feed instead of carriage return
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
break;
|
||||
case 0x00: // nopress
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
break;
|
||||
default: // all other keys
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x02: {
|
||||
// RAK14004
|
||||
uint8_t rDataBuf[8] = {0};
|
||||
uint8_t PrintDataBuf = 0;
|
||||
@@ -85,9 +180,12 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = PrintDataBuf;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
} else {
|
||||
// m5 cardkb
|
||||
i2cBus->requestFrom(CARDKB_ADDR, 1);
|
||||
break;
|
||||
}
|
||||
case 0x00: // CARDKB
|
||||
case 0x10: { // T-DECK
|
||||
|
||||
i2cBus->requestFrom((int)cardkb_found.address, 1);
|
||||
|
||||
while (i2cBus->available()) {
|
||||
char c = i2cBus->read();
|
||||
@@ -104,17 +202,19 @@ int32_t KbI2cBase::runOnce()
|
||||
break;
|
||||
case 0xb5: // Up
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
e.kbchar = 0xb5;
|
||||
break;
|
||||
case 0xb6: // Down
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
e.kbchar = 0xb6;
|
||||
break;
|
||||
case 0xb4: // Left
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
e.kbchar = c;
|
||||
e.kbchar = 0xb4;
|
||||
break;
|
||||
case 0xb7: // Right
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = c;
|
||||
e.kbchar = 0xb7;
|
||||
break;
|
||||
case 0x0d: // Enter
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
@@ -132,6 +232,10 @@ int32_t KbI2cBase::runOnce()
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 500;
|
||||
default:
|
||||
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
|
||||
}
|
||||
return 300;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "BBQ10Keyboard.h"
|
||||
#include "InputBroker.h"
|
||||
#include "Wire.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
@@ -16,4 +17,7 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
|
||||
const char *_originName;
|
||||
|
||||
TwoWire *i2cBus = 0;
|
||||
|
||||
BBQ10Keyboard Q10keyboard;
|
||||
bool is_sym = false;
|
||||
};
|
||||
|
||||
131
src/input/kbMatrixBase.cpp
Normal file
131
src/input/kbMatrixBase.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "kbMatrixBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
|
||||
const byte keys_cols[] = KEYS_COLS;
|
||||
const byte keys_rows[] = KEYS_ROWS;
|
||||
|
||||
#if INPUTBROKER_MATRIX_TYPE == 1
|
||||
|
||||
unsigned char KeyMap[3][sizeof(keys_rows)][sizeof(keys_cols)] = {{{' ', '.', 'm', 'n', 'b', 0xb6},
|
||||
{0x0d, 'l', 'k', 'j', 'h', 0xb4},
|
||||
{'p', 'o', 'i', 'u', 'y', 0xb5},
|
||||
{0x08, 'z', 'x', 'c', 'v', 0xb7},
|
||||
{'a', 's', 'd', 'f', 'g', 0x09},
|
||||
{'q', 'w', 'e', 'r', 't', 0x1a}},
|
||||
{// SHIFT
|
||||
{':', ';', 'M', 'N', 'B', 0xb6},
|
||||
{0x0d, 'L', 'K', 'J', 'H', 0xb4},
|
||||
{'P', 'O', 'I', 'U', 'Y', 0xb5},
|
||||
{0x08, 'Z', 'X', 'C', 'V', 0xb7},
|
||||
{'A', 'S', 'D', 'F', 'G', 0x09},
|
||||
{'Q', 'W', 'E', 'R', 'T', 0x1a}},
|
||||
{// SHIFT-SHIFT
|
||||
{'_', ',', '>', '<', '"', '{'},
|
||||
{'~', '-', '*', '&', '+', '['},
|
||||
{'0', '9', '8', '7', '6', '}'},
|
||||
{'=', '(', ')', '?', '/', ']'},
|
||||
{'!', '@', '#', '$', '%', '\\'},
|
||||
{'1', '2', '3', '4', '5', 0x1a}}};
|
||||
#endif
|
||||
|
||||
KbMatrixBase::KbMatrixBase(const char *name) : concurrency::OSThread(name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
int32_t KbMatrixBase::runOnce()
|
||||
{
|
||||
if (!INPUTBROKER_MATRIX_TYPE) {
|
||||
// Input device is not requested.
|
||||
return disable();
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do port setup
|
||||
firstTime = 0;
|
||||
for (byte i = 0; i < sizeof(keys_rows); i++) {
|
||||
pinMode(keys_rows[i], OUTPUT);
|
||||
digitalWrite(keys_rows[i], HIGH);
|
||||
}
|
||||
for (byte i = 0; i < sizeof(keys_cols); i++) {
|
||||
pinMode(keys_cols[i], INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
|
||||
key = 0;
|
||||
|
||||
if (INPUTBROKER_MATRIX_TYPE == 1) {
|
||||
// scan for keypresses
|
||||
for (byte i = 0; i < sizeof(keys_rows); i++) {
|
||||
digitalWrite(keys_rows[i], LOW);
|
||||
for (byte j = 0; j < sizeof(keys_cols); j++) {
|
||||
if (digitalRead(keys_cols[j]) == LOW) {
|
||||
key = KeyMap[shift][i][j];
|
||||
}
|
||||
}
|
||||
digitalWrite(keys_rows[i], HIGH);
|
||||
}
|
||||
// debounce
|
||||
if (key != prevkey) {
|
||||
if (key != 0) {
|
||||
LOG_DEBUG("Key 0x%x pressed\n", key);
|
||||
// reset shift now that we have a keypress
|
||||
InputEvent e;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
switch (key) {
|
||||
case 0x1b: // ESC
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
break;
|
||||
case 0x08: // Back
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
case 0xb5: // Up
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
break;
|
||||
case 0xb6: // Down
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
break;
|
||||
case 0xb4: // Left
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
case 0xb7: // Right
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
case 0x0d: // Enter
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
break;
|
||||
case 0x00: // nopress
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
break;
|
||||
case 0x1a: // Shift
|
||||
shift++;
|
||||
if (shift > 2) {
|
||||
shift = 0;
|
||||
}
|
||||
break;
|
||||
default: // all other keys
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = key;
|
||||
break;
|
||||
}
|
||||
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
prevkey = key;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_WARN("Unknown kb_model 0x%02x\n", INPUTBROKER_MATRIX_TYPE);
|
||||
return disable();
|
||||
}
|
||||
return 50; // Keyscan every 50msec to avoid key bounce
|
||||
}
|
||||
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
20
src/input/kbMatrixBase.h
Normal file
20
src/input/kbMatrixBase.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
class KbMatrixBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit KbMatrixBase(const char *name);
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
const char *_originName;
|
||||
bool firstTime = 1;
|
||||
int shift = 0;
|
||||
char key = 0;
|
||||
char prevkey = 0;
|
||||
};
|
||||
20
src/input/kbMatrixImpl.cpp
Normal file
20
src/input/kbMatrixImpl.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "kbMatrixImpl.h"
|
||||
#include "InputBroker.h"
|
||||
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
|
||||
KbMatrixImpl *kbMatrixImpl;
|
||||
|
||||
KbMatrixImpl::KbMatrixImpl() : KbMatrixBase("matrixKB") {}
|
||||
|
||||
void KbMatrixImpl::init()
|
||||
{
|
||||
if (!INPUTBROKER_MATRIX_TYPE) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
19
src/input/kbMatrixImpl.h
Normal file
19
src/input/kbMatrixImpl.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "kbMatrixBase.h"
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* @brief The idea behind this class to have static methods for the event handlers.
|
||||
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
|
||||
* Technically you can have as many rotary encoders hardver attached
|
||||
* to your device as you wish, but you always need to have separate event
|
||||
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
|
||||
*/
|
||||
class KbMatrixImpl : public KbMatrixBase
|
||||
{
|
||||
public:
|
||||
KbMatrixImpl();
|
||||
void init();
|
||||
};
|
||||
|
||||
extern KbMatrixImpl *kbMatrixImpl;
|
||||
30
src/main.cpp
30
src/main.cpp
@@ -96,7 +96,7 @@ ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
|
||||
|
||||
// The I2C address of the cardkb or RAK14004 (if found)
|
||||
ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
|
||||
// 0x02 for RAK14004 and 0x00 for cardkb
|
||||
// 0x02 for RAK14004, 0x00 for cardkb, 0x10 for T-Deck
|
||||
uint8_t kb_model;
|
||||
|
||||
// The I2C address of the RTC Module (if found)
|
||||
@@ -300,6 +300,15 @@ void setup()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef T_DECK
|
||||
// enable keyboard
|
||||
pinMode(KB_POWERON, OUTPUT);
|
||||
digitalWrite(KB_POWERON, HIGH);
|
||||
// There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time
|
||||
// otherwise keyboard and touch screen will not work
|
||||
delay(800);
|
||||
#endif
|
||||
|
||||
// Currently only the tbeam has a PMU
|
||||
// PMU initialization needs to be placed before i2c scanning
|
||||
power = new Power();
|
||||
@@ -372,8 +381,19 @@ void setup()
|
||||
kb_model = 0x02;
|
||||
break;
|
||||
case ScanI2C::DeviceType::CARDKB:
|
||||
kb_model = 0x00;
|
||||
break;
|
||||
case ScanI2C::DeviceType::TDECKKB:
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x10;
|
||||
break;
|
||||
case ScanI2C::DeviceType::BBQ10KB:
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x11;
|
||||
break;
|
||||
default:
|
||||
// use this as default since it's also just zero
|
||||
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
|
||||
kb_model = 0x00;
|
||||
}
|
||||
}
|
||||
@@ -458,8 +478,13 @@ void setup()
|
||||
#ifdef ARCH_NRF52
|
||||
nrf52Setup();
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_RP2040
|
||||
rp2040Setup();
|
||||
#endif
|
||||
|
||||
// We do this as early as possible because this loads preferences from flash
|
||||
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
|
||||
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
||||
nodeDB.init();
|
||||
|
||||
// If we're taking on the repeater role, use flood router
|
||||
@@ -524,6 +549,7 @@ void setup()
|
||||
#else
|
||||
// ESP32
|
||||
SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
SPI.setFrequency(4000000);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ extern uint32_t serialSinceMsec;
|
||||
// This will suppress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds();
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds();
|
||||
|
||||
meshtastic_DeviceMetadata getDeviceMetadata();
|
||||
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
/**
|
||||
* @file memGet.cpp
|
||||
* @brief Implementation of MemGet class that provides functions to get memory information.
|
||||
*
|
||||
* This file contains the implementation of MemGet class that provides functions to get
|
||||
* information about free heap, heap size, free psram and psram size. The functions are
|
||||
* implemented for ESP32 and NRF52 architectures. If the platform does not have heap
|
||||
* management function implemented, the functions return UINT32_MAX or 0.
|
||||
*/
|
||||
#include "memGet.h"
|
||||
#include "configuration.h"
|
||||
|
||||
MemGet memGet;
|
||||
|
||||
/**
|
||||
* Returns the amount of free heap memory in bytes.
|
||||
* @return uint32_t The amount of free heap memory in bytes.
|
||||
*/
|
||||
uint32_t MemGet::getFreeHeap()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -15,6 +28,10 @@ uint32_t MemGet::getFreeHeap()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the heap memory in bytes.
|
||||
* @return uint32_t The size of the heap memory in bytes.
|
||||
*/
|
||||
uint32_t MemGet::getHeapSize()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -27,6 +44,11 @@ uint32_t MemGet::getHeapSize()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of free psram memory in bytes.
|
||||
*
|
||||
* @return The amount of free psram memory in bytes.
|
||||
*/
|
||||
uint32_t MemGet::getFreePsram()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -36,6 +58,11 @@ uint32_t MemGet::getFreePsram()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the PSRAM memory.
|
||||
*
|
||||
* @return uint32_t The size of the PSRAM memory.
|
||||
*/
|
||||
uint32_t MemGet::getPsramSize()
|
||||
{
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -43,4 +70,4 @@ uint32_t MemGet::getPsramSize()
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignoring incoming msg, because we've already seen it", p);
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
|
||||
if (!moduleConfig.mqtt.enabled && config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
// cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater!
|
||||
@@ -49,10 +49,13 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
||||
|
||||
tosend->hop_limit--; // bump down the hop count
|
||||
|
||||
// If it is a traceRoute request, update the route that it went via me
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && traceRouteModule &&
|
||||
traceRouteModule->wantPacket(p)) {
|
||||
traceRouteModule->updateRoute(tosend);
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
// If it is a traceRoute request, update the route that it went via me
|
||||
if (traceRouteModule && traceRouteModule->wantPacket(p))
|
||||
traceRouteModule->updateRoute(tosend);
|
||||
// If it is a neighborInfo packet, update last_sent_by_id
|
||||
if (neighborInfoModule && neighborInfoModule->wantPacket(p))
|
||||
neighborInfoModule->updateLastSentById(tosend);
|
||||
}
|
||||
|
||||
LOG_INFO("Rebroadcasting received floodmsg to neighbors\n");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "PacketHistory.h"
|
||||
#include "Router.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include "modules/TraceRouteModule.h"
|
||||
|
||||
/**
|
||||
@@ -57,4 +58,4 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
* Look for broadcasts we need to rebroadcast
|
||||
*/
|
||||
virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override;
|
||||
};
|
||||
};
|
||||
@@ -82,8 +82,13 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
|
||||
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
|
||||
|
||||
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB.getMeshNode(mp->from)->has_user &&
|
||||
nodeInfoModule) {
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
|
||||
mp->decoded.portnum == meshtastic_PortNum_TELEMETRY_APP && mp->decoded.request_id > 0) {
|
||||
LOG_DEBUG(
|
||||
"Received telemetry response. Skip sending our NodeInfo because this potentially a Repeater which will ignore our "
|
||||
"request for its NodeInfo.\n");
|
||||
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB.getMeshNode(mp->from)->has_user &&
|
||||
nodeInfoModule) {
|
||||
LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel);
|
||||
nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel);
|
||||
}
|
||||
@@ -315,22 +320,22 @@ meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode()
|
||||
int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
{
|
||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||
meshtastic_NodeInfoLite *node = refreshLocalMeshNode();
|
||||
const meshtastic_NodeInfoLite *node = refreshLocalMeshNode();
|
||||
meshtastic_Position pos = meshtastic_Position_init_default;
|
||||
|
||||
if (newStatus->getHasLock()) {
|
||||
// load data from GPS object, will add timestamp + battery further down
|
||||
pos = gps->p;
|
||||
} else {
|
||||
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||
// the old position
|
||||
// The GPS has lost lock
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
LOG_DEBUG("onGPSchanged() - lost validLocation\n");
|
||||
#endif
|
||||
if (config.position.fixed_position) {
|
||||
LOG_WARN("Using fixed position\n");
|
||||
pos = ConvertToPosition(node->position);
|
||||
}
|
||||
}
|
||||
// Used fixed position if configured regalrdless of GPS lock
|
||||
if (config.position.fixed_position) {
|
||||
LOG_WARN("Using fixed position\n");
|
||||
pos = ConvertToPosition(node->position);
|
||||
}
|
||||
|
||||
// Finally add a fresh timestamp and battery level reading
|
||||
|
||||
@@ -48,6 +48,14 @@ class MeshService
|
||||
uint32_t oldFromNum = 0;
|
||||
|
||||
public:
|
||||
static bool isTextPayload(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (moduleConfig.range_test.enabled && p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
|
||||
return true;
|
||||
}
|
||||
return p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
|
||||
p->decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP;
|
||||
}
|
||||
/// Called when some new packets have arrived from one of the radios
|
||||
Observable<uint32_t> fromNumChanged;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "error.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include <ErriezCRC32.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
@@ -63,11 +64,7 @@ uint32_t error_address = 0;
|
||||
|
||||
static uint8_t ourMacAddr[6];
|
||||
|
||||
NodeDB::NodeDB()
|
||||
: nodes(devicestate.node_db), numNodes(&devicestate.node_db_count), meshNodes(devicestate.node_db_lite),
|
||||
numMeshNodes(&devicestate.node_db_lite_count)
|
||||
{
|
||||
}
|
||||
NodeDB::NodeDB() : meshNodes(devicestate.node_db_lite), numMeshNodes(&devicestate.node_db_lite_count) {}
|
||||
|
||||
/**
|
||||
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
|
||||
@@ -109,7 +106,6 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_TW;
|
||||
|
||||
// Enter super deep sleep soon and stay there not very long
|
||||
// radioConfig.preferences.mesh_sds_timeout_secs = 10;
|
||||
// radioConfig.preferences.sds_secs = 60;
|
||||
}
|
||||
|
||||
@@ -166,7 +162,7 @@ void NodeDB::installDefaultConfig()
|
||||
config.has_bluetooth = true;
|
||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL;
|
||||
|
||||
config.lora.sx126x_rx_boosted_gain = false;
|
||||
config.lora.sx126x_rx_boosted_gain = true;
|
||||
config.lora.tx_enabled =
|
||||
true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off)
|
||||
config.lora.override_duty_cycle = false;
|
||||
@@ -194,7 +190,9 @@ void NodeDB::installDefaultConfig()
|
||||
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
|
||||
// for backward compat, default position flags are ALT+MSL
|
||||
config.position.position_flags =
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL);
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_DOP);
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
config.display.screen_on_secs = 30;
|
||||
@@ -211,7 +209,6 @@ void NodeDB::initConfigIntervals()
|
||||
config.position.position_broadcast_secs = default_broadcast_interval_secs;
|
||||
|
||||
config.power.ls_secs = default_ls_secs;
|
||||
config.power.mesh_sds_timeout_secs = default_mesh_sds_timeout_secs;
|
||||
config.power.min_wake_secs = default_min_wake_secs;
|
||||
config.power.sds_secs = default_sds_secs;
|
||||
config.power.wait_bluetooth_secs = default_wait_bluetooth_secs;
|
||||
@@ -250,6 +247,14 @@ void NodeDB::installDefaultModuleConfig()
|
||||
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
|
||||
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
|
||||
|
||||
moduleConfig.has_neighbor_info = true;
|
||||
moduleConfig.neighbor_info.enabled = false;
|
||||
|
||||
moduleConfig.has_detection_sensor = true;
|
||||
moduleConfig.detection_sensor.enabled = false;
|
||||
moduleConfig.detection_sensor.detection_triggered_high = true;
|
||||
moduleConfig.detection_sensor.minimum_broadcast_secs = 45;
|
||||
|
||||
initModuleConfigIntervals();
|
||||
}
|
||||
|
||||
@@ -273,6 +278,7 @@ void NodeDB::initModuleConfigIntervals()
|
||||
moduleConfig.telemetry.device_update_interval = default_broadcast_interval_secs;
|
||||
moduleConfig.telemetry.environment_update_interval = default_broadcast_interval_secs;
|
||||
moduleConfig.telemetry.air_quality_interval = default_broadcast_interval_secs;
|
||||
moduleConfig.neighbor_info.update_interval = default_broadcast_interval_secs;
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultChannels()
|
||||
@@ -284,12 +290,11 @@ void NodeDB::installDefaultChannels()
|
||||
|
||||
void NodeDB::resetNodes()
|
||||
{
|
||||
devicestate.node_db_count = 0;
|
||||
memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
|
||||
|
||||
devicestate.node_db_lite_count = 0;
|
||||
memset(devicestate.node_db_lite, 0, sizeof(devicestate.node_db_lite));
|
||||
saveDeviceStateToDisk();
|
||||
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
|
||||
neighborInfoModule->resetNeighbors();
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultDeviceState()
|
||||
@@ -297,12 +302,11 @@ void NodeDB::installDefaultDeviceState()
|
||||
LOG_INFO("Installing default DeviceState\n");
|
||||
memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
||||
|
||||
*numNodes = 0;
|
||||
*numMeshNodes = 0;
|
||||
|
||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||
devicestate.has_my_node = true;
|
||||
devicestate.has_owner = true;
|
||||
devicestate.node_db_count = 0;
|
||||
devicestate.node_db_lite_count = 0;
|
||||
devicestate.version = DEVICESTATE_CUR_VER;
|
||||
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
||||
@@ -330,11 +334,9 @@ void NodeDB::init()
|
||||
int saveWhat = 0;
|
||||
|
||||
// likewise - we always want the app requirements to come from the running appload
|
||||
myNodeInfo.min_app_version = 20300; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
|
||||
myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand
|
||||
myNodeInfo.min_app_version = 30200; // format is Mmmss (where M is 1+the numeric major number. i.e. 30200 means 2.2.00
|
||||
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
|
||||
pickNewNodeNum();
|
||||
|
||||
// Set our board type so we can share it with others
|
||||
@@ -345,19 +347,6 @@ void NodeDB::init()
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
if (*numNodes > 0) {
|
||||
LOG_DEBUG("Legacy NodeDB detected... Migrating to NodeDBLite\n");
|
||||
uint32_t readIndex = 0;
|
||||
const meshtastic_NodeInfo *oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
|
||||
while (oldNodeInfo != NULL) {
|
||||
migrateToNodeInfoLite(oldNodeInfo);
|
||||
oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
|
||||
}
|
||||
LOG_DEBUG("Migration complete! Clearing out legacy NodeDB...\n");
|
||||
devicestate.node_db_count = 0;
|
||||
memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
@@ -367,7 +356,7 @@ void NodeDB::init()
|
||||
#endif
|
||||
|
||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||
LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, *numNodes);
|
||||
LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, *numMeshNodes);
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
@@ -613,14 +602,6 @@ void NodeDB::saveToDisk(int saveWhat)
|
||||
}
|
||||
}
|
||||
|
||||
const meshtastic_NodeInfo *NodeDB::readNextNodeInfo(uint32_t &readIndex)
|
||||
{
|
||||
if (readIndex < *numNodes)
|
||||
return &nodes[readIndex++];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex)
|
||||
{
|
||||
if (readIndex < *numMeshNodes)
|
||||
@@ -791,24 +772,13 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
||||
|
||||
uint8_t NodeDB::getMeshNodeChannel(NodeNum n)
|
||||
{
|
||||
meshtastic_NodeInfoLite *info = getMeshNode(n);
|
||||
const meshtastic_NodeInfoLite *info = getMeshNode(n);
|
||||
if (!info) {
|
||||
return 0; // defaults to PRIMARY
|
||||
}
|
||||
return info->channel;
|
||||
}
|
||||
|
||||
/// Find a node in our DB, return null for missing
|
||||
/// NOTE: This function might be called from an ISR
|
||||
meshtastic_NodeInfo *NodeDB::getNodeInfo(NodeNum n)
|
||||
{
|
||||
for (int i = 0; i < *numNodes; i++)
|
||||
if (nodes[i].num == n)
|
||||
return &nodes[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Find a node in our DB, return null for missing
|
||||
/// NOTE: This function might be called from an ISR
|
||||
meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
|
||||
@@ -827,7 +797,8 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
||||
|
||||
if (!lite) {
|
||||
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
if (screen)
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
// look for oldest node and erase it
|
||||
uint32_t oldest = UINT32_MAX;
|
||||
int oldestIndex = -1;
|
||||
@@ -854,57 +825,6 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
||||
return lite;
|
||||
}
|
||||
|
||||
void NodeDB::migrateToNodeInfoLite(const meshtastic_NodeInfo *node)
|
||||
{
|
||||
meshtastic_NodeInfoLite *lite = getMeshNode(node->num);
|
||||
|
||||
if (!lite) {
|
||||
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
// look for oldest node and erase it
|
||||
uint32_t oldest = UINT32_MAX;
|
||||
int oldestIndex = -1;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].last_heard < oldest) {
|
||||
oldest = meshNodes[i].last_heard;
|
||||
oldestIndex = i;
|
||||
}
|
||||
}
|
||||
// Shove the remaining nodes down the chain
|
||||
for (int i = oldestIndex; i < *numMeshNodes - 1; i++) {
|
||||
meshNodes[i] = meshNodes[i + 1];
|
||||
}
|
||||
(*numMeshNodes)--;
|
||||
}
|
||||
// add the node at the end
|
||||
lite = &meshNodes[(*numMeshNodes)++];
|
||||
|
||||
// everything is missing except the nodenum
|
||||
memset(lite, 0, sizeof(*lite));
|
||||
lite->num = node->num;
|
||||
lite->snr = node->snr;
|
||||
lite->last_heard = node->last_heard;
|
||||
lite->channel = node->channel;
|
||||
|
||||
if (node->has_position) {
|
||||
lite->has_position = true;
|
||||
lite->position.latitude_i = node->position.latitude_i;
|
||||
lite->position.longitude_i = node->position.longitude_i;
|
||||
lite->position.altitude = node->position.altitude;
|
||||
lite->position.location_source = node->position.location_source;
|
||||
lite->position.time = node->position.time;
|
||||
}
|
||||
if (node->has_user) {
|
||||
lite->has_user = true;
|
||||
lite->user = node->user;
|
||||
}
|
||||
if (node->has_device_metrics) {
|
||||
lite->has_device_metrics = true;
|
||||
lite->device_metrics = node->device_metrics;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Record an error that should be reported via analytics
|
||||
void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ DeviceState versions used to be defined in the .proto file but really only this
|
||||
#define SEGMENT_DEVICESTATE 4
|
||||
#define SEGMENT_CHANNELS 8
|
||||
|
||||
#define DEVICESTATE_CUR_VER 20
|
||||
#define DEVICESTATE_CUR_VER 22
|
||||
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
||||
|
||||
extern meshtastic_DeviceState devicestate;
|
||||
@@ -45,9 +45,6 @@ class NodeDB
|
||||
// Eventually use a smarter datastructure
|
||||
// HashMap<NodeNum, NodeInfo> nodes;
|
||||
// Note: these two references just point into our static array we serialize to/from disk
|
||||
meshtastic_NodeInfo *nodes;
|
||||
pb_size_t *numNodes;
|
||||
|
||||
meshtastic_NodeInfoLite *meshNodes;
|
||||
pb_size_t *numMeshNodes;
|
||||
|
||||
@@ -137,18 +134,6 @@ class NodeDB
|
||||
private:
|
||||
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
||||
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
||||
void migrateToNodeInfoLite(const meshtastic_NodeInfo *node);
|
||||
/// Find a node in our DB, return null for missing
|
||||
meshtastic_NodeInfo *getNodeInfo(NodeNum n);
|
||||
/// Allow the bluetooth layer to read our next nodeinfo record, or NULL if done reading
|
||||
const meshtastic_NodeInfo *readNextNodeInfo(uint32_t &readIndex);
|
||||
size_t getNumNodes() { return *numNodes; }
|
||||
|
||||
meshtastic_NodeInfo *getNodeByIndex(size_t x)
|
||||
{
|
||||
assert(x < *numNodes);
|
||||
return &nodes[x];
|
||||
}
|
||||
|
||||
/// Notify observers of changes to the DB
|
||||
void notifyObservers(bool forceUpdate = false)
|
||||
@@ -174,7 +159,6 @@ extern NodeDB nodeDB;
|
||||
|
||||
# prefs.position_broadcast_secs = FIXME possibly broadcast only once an hr
|
||||
prefs.wait_bluetooth_secs = 1 # Don't stay in bluetooth mode
|
||||
prefs.mesh_sds_timeout_secs = never
|
||||
# try to stay in light sleep one full day, then briefly wake and sleep again
|
||||
|
||||
prefs.ls_secs = oneday
|
||||
@@ -202,7 +186,6 @@ extern NodeDB nodeDB;
|
||||
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
|
||||
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
|
||||
#define default_wait_bluetooth_secs IF_ROUTER(1, 60)
|
||||
#define default_mesh_sds_timeout_secs IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60)
|
||||
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
|
||||
#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)
|
||||
#define default_min_wake_secs 10
|
||||
@@ -228,10 +211,6 @@ inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t d
|
||||
|
||||
/// Sometimes we will have Position objects that only have a time, so check for
|
||||
/// valid lat/lon
|
||||
static inline bool hasValidPosition(const meshtastic_NodeInfo *n)
|
||||
{
|
||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
||||
}
|
||||
static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n)
|
||||
{
|
||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
||||
|
||||
@@ -279,6 +279,14 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.remote_hardware = moduleConfig.remote_hardware;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_neighbor_info_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.neighbor_info = moduleConfig.neighbor_info;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_detection_sensor_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown module config type %d\n", config_state);
|
||||
}
|
||||
|
||||
@@ -153,7 +153,12 @@ void Router::setReceivedMessage()
|
||||
|
||||
meshtastic_QueueStatus Router::getQueueStatus()
|
||||
{
|
||||
return iface->getQueueStatus();
|
||||
if (!iface) {
|
||||
meshtastic_QueueStatus qs;
|
||||
qs.res = qs.mesh_packet_id = qs.free = qs.maxlen = 0;
|
||||
return qs;
|
||||
} else
|
||||
return iface->getQueueStatus();
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
|
||||
|
||||
@@ -53,7 +53,13 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_AUDIO_CONFIG = 7,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG = 8
|
||||
meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG = 8,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_NEIGHBORINFO_CONFIG = 9,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG = 10,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11
|
||||
} meshtastic_AdminMessage_ModuleConfigType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -172,8 +178,8 @@ extern "C" {
|
||||
#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_BLUETOOTH_CONFIG+1))
|
||||
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG+1))
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG
|
||||
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG+1))
|
||||
|
||||
#define meshtastic_AdminMessage_payload_variant_get_config_request_ENUMTYPE meshtastic_AdminMessage_ConfigType
|
||||
#define meshtastic_AdminMessage_payload_variant_get_module_config_request_ENUMTYPE meshtastic_AdminMessage_ModuleConfigType
|
||||
|
||||
@@ -51,8 +51,9 @@ typedef enum _meshtastic_Config_DeviceConfig_RebroadcastMode {
|
||||
} meshtastic_Config_DeviceConfig_RebroadcastMode;
|
||||
|
||||
/* Bit field of boolean configuration options, indicating which optional
|
||||
fields to include when assembling POSITION messages
|
||||
Longitude and latitude are always included (also time if GPS-synced)
|
||||
fields to include when assembling POSITION messages.
|
||||
Longitude, latitude, altitude, speed, heading, and DOP
|
||||
are always included (also time if GPS-synced)
|
||||
NOTE: the more fields are included, the larger the message will be -
|
||||
leading to longer airtime and a higher risk of packet loss */
|
||||
typedef enum _meshtastic_Config_PositionConfig_PositionFlags {
|
||||
@@ -269,7 +270,7 @@ typedef struct _meshtastic_Config_PositionConfig {
|
||||
uint32_t tx_gpio;
|
||||
/* The minimum distance in meters traveled (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
|
||||
uint32_t broadcast_smart_minimum_distance;
|
||||
/* The minumum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
|
||||
/* The minimum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
|
||||
uint32_t broadcast_smart_minimum_interval_secs;
|
||||
} meshtastic_Config_PositionConfig;
|
||||
|
||||
@@ -292,11 +293,6 @@ typedef struct _meshtastic_Config_PowerConfig {
|
||||
The number of seconds for to wait before turning off BLE in No Bluetooth states
|
||||
0 for default of 1 minute */
|
||||
uint32_t wait_bluetooth_secs;
|
||||
/* Mesh Super Deep Sleep Timeout Seconds
|
||||
While in Light Sleep if this value is exceeded we will lower into super deep sleep
|
||||
for sds_secs (default 1 year) or a button press
|
||||
0 for default of two hours, MAXUINT for disabled */
|
||||
uint32_t mesh_sds_timeout_secs;
|
||||
/* Super Deep Sleep Seconds
|
||||
While in Light Sleep if mesh_sds_timeout_secs is exceeded we will lower into super deep sleep
|
||||
for this value (default 1 year) or a button press
|
||||
@@ -536,7 +532,7 @@ extern "C" {
|
||||
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
|
||||
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0}
|
||||
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
|
||||
@@ -545,7 +541,7 @@ extern "C" {
|
||||
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
|
||||
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0}
|
||||
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
|
||||
@@ -577,7 +573,6 @@ extern "C" {
|
||||
#define meshtastic_Config_PowerConfig_on_battery_shutdown_after_secs_tag 2
|
||||
#define meshtastic_Config_PowerConfig_adc_multiplier_override_tag 3
|
||||
#define meshtastic_Config_PowerConfig_wait_bluetooth_secs_tag 4
|
||||
#define meshtastic_Config_PowerConfig_mesh_sds_timeout_secs_tag 5
|
||||
#define meshtastic_Config_PowerConfig_sds_secs_tag 6
|
||||
#define meshtastic_Config_PowerConfig_ls_secs_tag 7
|
||||
#define meshtastic_Config_PowerConfig_min_wake_secs_tag 8
|
||||
@@ -682,7 +677,6 @@ X(a, STATIC, SINGULAR, BOOL, is_power_saving, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, on_battery_shutdown_after_secs, 2) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, adc_multiplier_override, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sds_secs, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ls_secs, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 8) \
|
||||
@@ -780,7 +774,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
|
||||
#define meshtastic_Config_NetworkConfig_size 195
|
||||
#define meshtastic_Config_PositionConfig_size 54
|
||||
#define meshtastic_Config_PowerConfig_size 46
|
||||
#define meshtastic_Config_PowerConfig_size 40
|
||||
#define meshtastic_Config_size 198
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -75,6 +75,12 @@ typedef struct _meshtastic_LocalModuleConfig {
|
||||
/* The part of the config that is specific to the Neighbor Info module */
|
||||
bool has_neighbor_info;
|
||||
meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info;
|
||||
/* The part of the config that is specific to the Ambient Lighting module */
|
||||
bool has_ambient_lighting;
|
||||
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
|
||||
/* The part of the config that is specific to the Detection Sensor module */
|
||||
bool has_detection_sensor;
|
||||
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
|
||||
} meshtastic_LocalModuleConfig;
|
||||
|
||||
|
||||
@@ -84,9 +90,9 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_LocalConfig_init_default {false, meshtastic_Config_DeviceConfig_init_default, false, meshtastic_Config_PositionConfig_init_default, false, meshtastic_Config_PowerConfig_init_default, false, meshtastic_Config_NetworkConfig_init_default, false, meshtastic_Config_DisplayConfig_init_default, false, meshtastic_Config_LoRaConfig_init_default, false, meshtastic_Config_BluetoothConfig_init_default, 0}
|
||||
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default}
|
||||
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_default}
|
||||
#define meshtastic_LocalConfig_init_zero {false, meshtastic_Config_DeviceConfig_init_zero, false, meshtastic_Config_PositionConfig_init_zero, false, meshtastic_Config_PowerConfig_init_zero, false, meshtastic_Config_NetworkConfig_init_zero, false, meshtastic_Config_DisplayConfig_init_zero, false, meshtastic_Config_LoRaConfig_init_zero, false, meshtastic_Config_BluetoothConfig_init_zero, 0}
|
||||
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero}
|
||||
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_zero}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_LocalConfig_device_tag 1
|
||||
@@ -108,6 +114,8 @@ extern "C" {
|
||||
#define meshtastic_LocalModuleConfig_audio_tag 9
|
||||
#define meshtastic_LocalModuleConfig_remote_hardware_tag 10
|
||||
#define meshtastic_LocalModuleConfig_neighbor_info_tag 11
|
||||
#define meshtastic_LocalModuleConfig_ambient_lighting_tag 12
|
||||
#define meshtastic_LocalModuleConfig_detection_sensor_tag 13
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_LocalConfig_FIELDLIST(X, a) \
|
||||
@@ -140,7 +148,9 @@ X(a, STATIC, OPTIONAL, MESSAGE, canned_message, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, audio, 9) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11)
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, ambient_lighting, 12) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13)
|
||||
#define meshtastic_LocalModuleConfig_CALLBACK NULL
|
||||
#define meshtastic_LocalModuleConfig_DEFAULT NULL
|
||||
#define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
||||
@@ -153,6 +163,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11)
|
||||
#define meshtastic_LocalModuleConfig_audio_MSGTYPE meshtastic_ModuleConfig_AudioConfig
|
||||
#define meshtastic_LocalModuleConfig_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig
|
||||
#define meshtastic_LocalModuleConfig_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
|
||||
#define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
||||
#define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_LocalConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
@@ -162,8 +174,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_LocalConfig_size 461
|
||||
#define meshtastic_LocalModuleConfig_size 547
|
||||
#define meshtastic_LocalConfig_size 455
|
||||
#define meshtastic_LocalModuleConfig_size 609
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -59,6 +59,10 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_TLORA_T3_S3 = 16,
|
||||
/* B&Q Consulting Nano G1 Explorer: https://wiki.uniteng.com/en/meshtastic/nano-g1-explorer */
|
||||
meshtastic_HardwareModel_NANO_G1_EXPLORER = 17,
|
||||
/* B&Q Consulting Nano G2 Ultra: https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra */
|
||||
meshtastic_HardwareModel_NANO_G2_ULTRA = 18,
|
||||
/* LoRAType device: https://loratype.org/ */
|
||||
meshtastic_HardwareModel_LORA_TYPE = 19,
|
||||
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
|
||||
meshtastic_HardwareModel_STATION_G1 = 25,
|
||||
/* RAK11310 (RP2040 + SX1262) */
|
||||
@@ -101,10 +105,14 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER = 48,
|
||||
/* Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display */
|
||||
meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER = 49,
|
||||
/* LilyGo T-Deck with ESP32-S3 CPU, Keyboard, and IPS display */
|
||||
/* LilyGo T-Deck with ESP32-S3 CPU, Keyboard and IPS display */
|
||||
meshtastic_HardwareModel_T_DECK = 50,
|
||||
/* LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display */
|
||||
meshtastic_HardwareModel_T_WATCH_S3 = 51,
|
||||
/* Bobricius Picomputer with ESP32-S3 CPU, Keyboard and IPS display */
|
||||
meshtastic_HardwareModel_PICOMPUTER_S3 = 52,
|
||||
/* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */
|
||||
meshtastic_HardwareModel_HELTEC_HT62 = 53,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
@@ -147,7 +155,7 @@ typedef enum _meshtastic_CriticalErrorCode {
|
||||
/* Radio transmit hardware failure. We sent data to the radio chip, but it didn't
|
||||
reply with an interrupt. */
|
||||
meshtastic_CriticalErrorCode_TRANSMIT_FAILED = 8,
|
||||
/* We detected that the main CPU voltage dropped below the minumum acceptable value */
|
||||
/* We detected that the main CPU voltage dropped below the minimum acceptable value */
|
||||
meshtastic_CriticalErrorCode_BROWNOUT = 9,
|
||||
/* Selftest of SX1262 radio chip failed */
|
||||
meshtastic_CriticalErrorCode_SX1262_FAILURE = 10,
|
||||
@@ -228,9 +236,9 @@ typedef enum _meshtastic_Routing_Error {
|
||||
to make sure that critical packets are sent ASAP.
|
||||
In the case of meshtastic that means we want to send protocol acks as soon as possible
|
||||
(to prevent unneeded retransmissions), we want routing messages to be sent next,
|
||||
then messages marked as reliable and finally ‘background’ packets like periodic position updates.
|
||||
then messages marked as reliable and finally 'background' packets like periodic position updates.
|
||||
So I bit the bullet and implemented a new (internal - not sent over the air)
|
||||
field in MeshPacket called ‘priority’.
|
||||
field in MeshPacket called 'priority'.
|
||||
And the transmission queue in the router object is now a priority queue. */
|
||||
typedef enum _meshtastic_MeshPacket_Priority {
|
||||
/* Treated as Priority.DEFAULT */
|
||||
@@ -603,60 +611,12 @@ typedef struct _meshtastic_MyNodeInfo {
|
||||
/* Tells the phone what our node number is, default starting value is
|
||||
lowbyte of macaddr, but it will be fixed if that is already in use */
|
||||
uint32_t my_node_num;
|
||||
/* Deprecated in 2.1.x (Source from device_metadata)
|
||||
Note: This flag merely means we detected a hardware GPS in our node.
|
||||
Not the same as UserPreferences.location_sharing */
|
||||
bool has_gps;
|
||||
/* Deprecated in 2.1.x
|
||||
The maximum number of 'software' channels that can be set on this node. */
|
||||
uint32_t max_channels;
|
||||
/* Deprecated in 2.1.x (Source from device_metadata)
|
||||
0.0.5 etc... */
|
||||
char firmware_version[18];
|
||||
/* An error message we'd like to report back to the mothership through analytics.
|
||||
It indicates a serious bug occurred on the device, the device coped with it,
|
||||
but we still want to tell the devs about the bug.
|
||||
This field will be cleared after the phone reads MyNodeInfo
|
||||
(i.e. it will only be reported once)
|
||||
a numeric error code to go with error message, zero means no error */
|
||||
meshtastic_CriticalErrorCode error_code;
|
||||
/* A numeric error address (nonzero if available) */
|
||||
uint32_t error_address;
|
||||
/* The total number of errors this node has ever encountered
|
||||
(well - since the last time we discarded preferences) */
|
||||
uint32_t error_count;
|
||||
/* The total number of reboots this node has ever encountered
|
||||
(well - since the last time we discarded preferences) */
|
||||
uint32_t reboot_count;
|
||||
/* Deprecated in 2.1.x
|
||||
Calculated bitrate of the current channel (in Bytes Per Second) */
|
||||
float bitrate;
|
||||
/* Deprecated in 2.1.x
|
||||
How long before we consider a message abandoned and we can clear our
|
||||
caches of any messages in flight Normally quite large to handle the worst case
|
||||
message delivery time, 5 minutes.
|
||||
Formerly called FLOOD_EXPIRE_TIME in the device code */
|
||||
uint32_t message_timeout_msec;
|
||||
/* The minimum app version that can talk to this device.
|
||||
Phone/PC apps should compare this to their build number and if too low tell the user they must update their app */
|
||||
uint32_t min_app_version;
|
||||
/* Deprecated in 2.1.x (Only used on device to keep track of utilization)
|
||||
24 time windows of 1hr each with the airtime transmitted out of the device per hour. */
|
||||
pb_size_t air_period_tx_count;
|
||||
uint32_t air_period_tx[8];
|
||||
/* Deprecated in 2.1.x (Only used on device to keep track of utilization)
|
||||
24 time windows of 1hr each with the airtime of valid packets for your mesh. */
|
||||
pb_size_t air_period_rx_count;
|
||||
uint32_t air_period_rx[8];
|
||||
/* Deprecated in 2.1.x (Source from DeviceMetadata instead)
|
||||
Is the device wifi capable? */
|
||||
bool has_wifi;
|
||||
/* Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads)
|
||||
Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). */
|
||||
float channel_utilization;
|
||||
/* Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads)
|
||||
Percent of airtime for transmission used within the last hour. */
|
||||
float air_util_tx;
|
||||
} meshtastic_MyNodeInfo;
|
||||
|
||||
/* Debug output from the device.
|
||||
@@ -727,6 +687,12 @@ typedef struct _meshtastic_Neighbor {
|
||||
uint32_t node_id;
|
||||
/* SNR of last heard message */
|
||||
float snr;
|
||||
/* Reception time (in secs since 1970) of last message that was last sent by this ID.
|
||||
Note: this is for local storage only and will not be sent out over the mesh. */
|
||||
uint32_t last_rx_time;
|
||||
/* Broadcast interval of this neighbor (in seconds).
|
||||
Note: this is for local storage only and will not be sent out over the mesh. */
|
||||
uint32_t node_broadcast_interval_secs;
|
||||
} meshtastic_Neighbor;
|
||||
|
||||
/* Full info on edges for a single node */
|
||||
@@ -735,6 +701,8 @@ typedef struct _meshtastic_NeighborInfo {
|
||||
uint32_t node_id;
|
||||
/* Field to pass neighbor info for the next sending cycle */
|
||||
uint32_t last_sent_by_id;
|
||||
/* Broadcast interval of the represented node (in seconds) */
|
||||
uint32_t node_broadcast_interval_secs;
|
||||
/* The list of out edges from this node */
|
||||
pb_size_t neighbors_count;
|
||||
meshtastic_Neighbor neighbors[10];
|
||||
@@ -869,7 +837,6 @@ extern "C" {
|
||||
#define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed
|
||||
|
||||
|
||||
#define meshtastic_MyNodeInfo_error_code_ENUMTYPE meshtastic_CriticalErrorCode
|
||||
|
||||
#define meshtastic_LogRecord_level_ENUMTYPE meshtastic_LogRecord_Level
|
||||
|
||||
@@ -894,14 +861,14 @@ extern "C" {
|
||||
#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}
|
||||
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0}
|
||||
#define meshtastic_MyNodeInfo_init_default {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
|
||||
#define meshtastic_MyNodeInfo_init_default {0, 0, 0}
|
||||
#define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||
#define meshtastic_QueueStatus_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}}
|
||||
#define meshtastic_ToRadio_init_default {0, {meshtastic_MeshPacket_init_default}}
|
||||
#define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}}
|
||||
#define meshtastic_NeighborInfo_init_default {0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}}
|
||||
#define meshtastic_Neighbor_init_default {0, 0}
|
||||
#define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}}
|
||||
#define meshtastic_Neighbor_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
|
||||
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0}
|
||||
@@ -912,14 +879,14 @@ extern "C" {
|
||||
#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}
|
||||
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0}
|
||||
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
|
||||
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0}
|
||||
#define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||
#define meshtastic_QueueStatus_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}}
|
||||
#define meshtastic_ToRadio_init_zero {0, {meshtastic_MeshPacket_init_zero}}
|
||||
#define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}}
|
||||
#define meshtastic_NeighborInfo_init_zero {0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}}
|
||||
#define meshtastic_Neighbor_init_zero {0, 0}
|
||||
#define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}}
|
||||
#define meshtastic_Neighbor_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
@@ -996,21 +963,8 @@ extern "C" {
|
||||
#define meshtastic_NodeInfo_device_metrics_tag 6
|
||||
#define meshtastic_NodeInfo_channel_tag 7
|
||||
#define meshtastic_MyNodeInfo_my_node_num_tag 1
|
||||
#define meshtastic_MyNodeInfo_has_gps_tag 2
|
||||
#define meshtastic_MyNodeInfo_max_channels_tag 3
|
||||
#define meshtastic_MyNodeInfo_firmware_version_tag 4
|
||||
#define meshtastic_MyNodeInfo_error_code_tag 5
|
||||
#define meshtastic_MyNodeInfo_error_address_tag 6
|
||||
#define meshtastic_MyNodeInfo_error_count_tag 7
|
||||
#define meshtastic_MyNodeInfo_reboot_count_tag 8
|
||||
#define meshtastic_MyNodeInfo_bitrate_tag 9
|
||||
#define meshtastic_MyNodeInfo_message_timeout_msec_tag 10
|
||||
#define meshtastic_MyNodeInfo_min_app_version_tag 11
|
||||
#define meshtastic_MyNodeInfo_air_period_tx_tag 12
|
||||
#define meshtastic_MyNodeInfo_air_period_rx_tag 13
|
||||
#define meshtastic_MyNodeInfo_has_wifi_tag 14
|
||||
#define meshtastic_MyNodeInfo_channel_utilization_tag 15
|
||||
#define meshtastic_MyNodeInfo_air_util_tx_tag 16
|
||||
#define meshtastic_LogRecord_message_tag 1
|
||||
#define meshtastic_LogRecord_time_tag 2
|
||||
#define meshtastic_LogRecord_source_tag 3
|
||||
@@ -1028,9 +982,12 @@ extern "C" {
|
||||
#define meshtastic_Compressed_data_tag 2
|
||||
#define meshtastic_Neighbor_node_id_tag 1
|
||||
#define meshtastic_Neighbor_snr_tag 2
|
||||
#define meshtastic_Neighbor_last_rx_time_tag 3
|
||||
#define meshtastic_Neighbor_node_broadcast_interval_secs_tag 4
|
||||
#define meshtastic_NeighborInfo_node_id_tag 1
|
||||
#define meshtastic_NeighborInfo_last_sent_by_id_tag 2
|
||||
#define meshtastic_NeighborInfo_neighbors_tag 3
|
||||
#define meshtastic_NeighborInfo_node_broadcast_interval_secs_tag 3
|
||||
#define meshtastic_NeighborInfo_neighbors_tag 4
|
||||
#define meshtastic_DeviceMetadata_firmware_version_tag 1
|
||||
#define meshtastic_DeviceMetadata_device_state_version_tag 2
|
||||
#define meshtastic_DeviceMetadata_canShutdown_tag 3
|
||||
@@ -1173,21 +1130,8 @@ X(a, STATIC, SINGULAR, UINT32, channel, 7)
|
||||
|
||||
#define meshtastic_MyNodeInfo_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, max_channels, 3) \
|
||||
X(a, STATIC, SINGULAR, STRING, firmware_version, 4) \
|
||||
X(a, STATIC, SINGULAR, UENUM, error_code, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error_address, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error_count, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, reboot_count, 8) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, bitrate, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, message_timeout_msec, 10) \
|
||||
X(a, STATIC, SINGULAR, UINT32, min_app_version, 11) \
|
||||
X(a, STATIC, REPEATED, UINT32, air_period_tx, 12) \
|
||||
X(a, STATIC, REPEATED, UINT32, air_period_rx, 13) \
|
||||
X(a, STATIC, SINGULAR, BOOL, has_wifi, 14) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, channel_utilization, 15) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, air_util_tx, 16)
|
||||
X(a, STATIC, SINGULAR, UINT32, min_app_version, 11)
|
||||
#define meshtastic_MyNodeInfo_CALLBACK NULL
|
||||
#define meshtastic_MyNodeInfo_DEFAULT NULL
|
||||
|
||||
@@ -1257,14 +1201,17 @@ X(a, STATIC, SINGULAR, BYTES, data, 2)
|
||||
#define meshtastic_NeighborInfo_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, node_id, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, last_sent_by_id, 2) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, neighbors, 3)
|
||||
X(a, STATIC, SINGULAR, UINT32, node_broadcast_interval_secs, 3) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, neighbors, 4)
|
||||
#define meshtastic_NeighborInfo_CALLBACK NULL
|
||||
#define meshtastic_NeighborInfo_DEFAULT NULL
|
||||
#define meshtastic_NeighborInfo_neighbors_MSGTYPE meshtastic_Neighbor
|
||||
|
||||
#define meshtastic_Neighbor_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, node_id, 1) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 2)
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 2) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, last_rx_time, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, node_broadcast_interval_secs, 4)
|
||||
#define meshtastic_Neighbor_CALLBACK NULL
|
||||
#define meshtastic_Neighbor_DEFAULT NULL
|
||||
|
||||
@@ -1329,9 +1276,9 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
#define meshtastic_LogRecord_size 81
|
||||
#define meshtastic_MeshPacket_size 321
|
||||
#define meshtastic_MqttClientProxyMessage_size 501
|
||||
#define meshtastic_MyNodeInfo_size 179
|
||||
#define meshtastic_NeighborInfo_size 142
|
||||
#define meshtastic_Neighbor_size 11
|
||||
#define meshtastic_MyNodeInfo_size 18
|
||||
#define meshtastic_NeighborInfo_size 258
|
||||
#define meshtastic_Neighbor_size 22
|
||||
#define meshtastic_NodeInfo_size 261
|
||||
#define meshtastic_Position_size 137
|
||||
#define meshtastic_QueueStatus_size 23
|
||||
|
||||
@@ -18,6 +18,9 @@ PB_BIND(meshtastic_ModuleConfig_RemoteHardwareConfig, meshtastic_ModuleConfig_Re
|
||||
PB_BIND(meshtastic_ModuleConfig_NeighborInfoConfig, meshtastic_ModuleConfig_NeighborInfoConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_DetectionSensorConfig, meshtastic_ModuleConfig_DetectionSensorConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_AudioConfig, meshtastic_ModuleConfig_AudioConfig, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -125,6 +125,33 @@ typedef struct _meshtastic_ModuleConfig_NeighborInfoConfig {
|
||||
uint32_t update_interval;
|
||||
} meshtastic_ModuleConfig_NeighborInfoConfig;
|
||||
|
||||
/* Detection Sensor Module Config */
|
||||
typedef struct _meshtastic_ModuleConfig_DetectionSensorConfig {
|
||||
/* Whether the Module is enabled */
|
||||
bool enabled;
|
||||
/* Interval in seconds of how often we can send a message to the mesh when a state change is detected */
|
||||
uint32_t minimum_broadcast_secs;
|
||||
/* Interval in seconds of how often we should send a message to the mesh with the current state regardless of changes
|
||||
When set to 0, only state changes will be broadcasted
|
||||
Works as a sort of status heartbeat for peace of mind */
|
||||
uint32_t state_broadcast_secs;
|
||||
/* Send ASCII bell with alert message
|
||||
Useful for triggering ext. notification on bell */
|
||||
bool send_bell;
|
||||
/* Friendly name used to format message sent to mesh
|
||||
Example: A name "Motion" would result in a message "Motion detected"
|
||||
Maximum length of 20 characters */
|
||||
char name[20];
|
||||
/* GPIO pin to monitor for state changes */
|
||||
uint8_t monitor_pin;
|
||||
/* Whether or not the GPIO pin state detection is triggered on HIGH (1)
|
||||
Otherwise LOW (0) */
|
||||
bool detection_triggered_high;
|
||||
/* Whether or not use INPUT_PULLUP mode for GPIO pin
|
||||
Only applicable if the board uses pull-up resistors on the pin */
|
||||
bool use_pullup;
|
||||
} meshtastic_ModuleConfig_DetectionSensorConfig;
|
||||
|
||||
/* Audio Config for codec2 voice */
|
||||
typedef struct _meshtastic_ModuleConfig_AudioConfig {
|
||||
/* Whether Audio is enabled */
|
||||
@@ -342,6 +369,8 @@ typedef struct _meshtastic_ModuleConfig {
|
||||
meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info;
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
|
||||
} payload_variant;
|
||||
} meshtastic_ModuleConfig;
|
||||
|
||||
@@ -375,6 +404,7 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
|
||||
#define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud
|
||||
|
||||
#define meshtastic_ModuleConfig_SerialConfig_baud_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Baud
|
||||
@@ -397,6 +427,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0, 0, 0, {meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default}}
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0}
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_default {0, 0, 0, 0, "", 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
@@ -410,6 +441,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0, 0, 0, {meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero}}
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0}
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_zero {0, 0, 0, 0, "", 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
@@ -432,6 +464,14 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_proxy_to_client_enabled_tag 9
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_minimum_broadcast_secs_tag 2
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_state_broadcast_secs_tag 3
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_send_bell_tag 4
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_name_tag 5
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_monitor_pin_tag 6
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_detection_triggered_high_tag 7
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_use_pullup_tag 8
|
||||
#define meshtastic_ModuleConfig_AudioConfig_codec2_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_AudioConfig_ptt_pin_tag 2
|
||||
#define meshtastic_ModuleConfig_AudioConfig_bitrate_tag 3
|
||||
@@ -509,6 +549,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_remote_hardware_tag 9
|
||||
#define meshtastic_ModuleConfig_neighbor_info_tag 10
|
||||
#define meshtastic_ModuleConfig_ambient_lighting_tag 11
|
||||
#define meshtastic_ModuleConfig_detection_sensor_tag 12
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_ModuleConfig_FIELDLIST(X, a) \
|
||||
@@ -522,7 +563,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_varia
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio), 8) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_variant.detection_sensor), 12)
|
||||
#define meshtastic_ModuleConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_DEFAULT NULL
|
||||
#define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
||||
@@ -536,6 +578,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_var
|
||||
#define meshtastic_ModuleConfig_payload_variant_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
||||
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
@@ -564,6 +607,18 @@ X(a, STATIC, SINGULAR, UINT32, update_interval, 2)
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_DEFAULT NULL
|
||||
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, minimum_broadcast_secs, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, state_broadcast_secs, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, send_bell, 4) \
|
||||
X(a, STATIC, SINGULAR, STRING, name, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, monitor_pin, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, detection_triggered_high, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, use_pullup, 8)
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_DEFAULT NULL
|
||||
|
||||
#define meshtastic_ModuleConfig_AudioConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ptt_pin, 2) \
|
||||
@@ -667,6 +722,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_MQTTConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_RemoteHardwareConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_NeighborInfoConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_DetectionSensorConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_AudioConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_SerialConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_ExternalNotificationConfig_msg;
|
||||
@@ -682,6 +738,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_fields &meshtastic_ModuleConfig_MQTTConfig_msg
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_fields &meshtastic_ModuleConfig_RemoteHardwareConfig_msg
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_fields &meshtastic_ModuleConfig_NeighborInfoConfig_msg
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_fields &meshtastic_ModuleConfig_DetectionSensorConfig_msg
|
||||
#define meshtastic_ModuleConfig_AudioConfig_fields &meshtastic_ModuleConfig_AudioConfig_msg
|
||||
#define meshtastic_ModuleConfig_SerialConfig_fields &meshtastic_ModuleConfig_SerialConfig_msg
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_fields &meshtastic_ModuleConfig_ExternalNotificationConfig_msg
|
||||
@@ -696,6 +753,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_size 14
|
||||
#define meshtastic_ModuleConfig_AudioConfig_size 19
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49
|
||||
#define meshtastic_ModuleConfig_DetectionSensorConfig_size 44
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_size 222
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
|
||||
|
||||
@@ -25,75 +25,101 @@
|
||||
typedef enum _meshtastic_PortNum {
|
||||
/* Deprecated: do not use in new code (formerly called OPAQUE)
|
||||
A message sent from a device outside of the mesh, in a form the mesh does not understand
|
||||
NOTE: This must be 0, because it is documented in IMeshService.aidl to be so */
|
||||
NOTE: This must be 0, because it is documented in IMeshService.aidl to be so
|
||||
ENCODING: binary undefined */
|
||||
meshtastic_PortNum_UNKNOWN_APP = 0,
|
||||
/* A simple UTF-8 text message, which even the little micros in the mesh
|
||||
can understand and show on their screen eventually in some circumstances
|
||||
even signal might send messages in this form (see below) */
|
||||
even signal might send messages in this form (see below)
|
||||
ENCODING: UTF-8 Plaintext (?) */
|
||||
meshtastic_PortNum_TEXT_MESSAGE_APP = 1,
|
||||
/* Reserved for built-in GPIO/example app.
|
||||
See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number */
|
||||
See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_REMOTE_HARDWARE_APP = 2,
|
||||
/* The built-in position messaging app.
|
||||
Payload is a [Position](/docs/developers/protobufs/api#position) message */
|
||||
Payload is a [Position](/docs/developers/protobufs/api#position) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_POSITION_APP = 3,
|
||||
/* The built-in user info app.
|
||||
Payload is a [User](/docs/developers/protobufs/api#user) message */
|
||||
Payload is a [User](/docs/developers/protobufs/api#user) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_NODEINFO_APP = 4,
|
||||
/* Protocol control packets for mesh protocol use.
|
||||
Payload is a [Routing](/docs/developers/protobufs/api#routing) message */
|
||||
Payload is a [Routing](/docs/developers/protobufs/api#routing) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_ROUTING_APP = 5,
|
||||
/* Admin control packets.
|
||||
Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message */
|
||||
Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_ADMIN_APP = 6,
|
||||
/* Compressed TEXT_MESSAGE payloads. */
|
||||
/* Compressed TEXT_MESSAGE payloads.
|
||||
ENCODING: UTF-8 Plaintext (?) with Unishox2 Compression
|
||||
NOTE: The Device Firmware converts a TEXT_MESSAGE_APP to TEXT_MESSAGE_COMPRESSED_APP if the compressed
|
||||
payload is shorter. There's no need for app developers to do this themselves. Also the firmware will decompress
|
||||
any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP. */
|
||||
meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7,
|
||||
/* Waypoint payloads.
|
||||
Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message */
|
||||
Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_WAYPOINT_APP = 8,
|
||||
/* Audio Payloads.
|
||||
Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now */
|
||||
Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now
|
||||
ENCODING: codec2 audio frames
|
||||
NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate.
|
||||
This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. */
|
||||
meshtastic_PortNum_AUDIO_APP = 9,
|
||||
/* Payloads for clients with a network connection proxying MQTT pub/sub to the device */
|
||||
meshtastic_PortNum_MQTT_CLIENT_PROXY_APP = 10,
|
||||
/* Same as Text Message but originating from Detection Sensor Module. */
|
||||
meshtastic_PortNum_DETECTION_SENSOR_APP = 10,
|
||||
/* Provides a 'ping' service that replies to any packet it receives.
|
||||
Also serves as a small example module. */
|
||||
Also serves as a small example module.
|
||||
ENCODING: ASCII Plaintext */
|
||||
meshtastic_PortNum_REPLY_APP = 32,
|
||||
/* Used for the python IP tunnel feature */
|
||||
/* Used for the python IP tunnel feature
|
||||
ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on. */
|
||||
meshtastic_PortNum_IP_TUNNEL_APP = 33,
|
||||
/* Provides a hardware serial interface to send and receive from the Meshtastic network.
|
||||
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
|
||||
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
|
||||
Maximum packet size of 240 bytes.
|
||||
Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp. */
|
||||
Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp.
|
||||
ENCODING: binary undefined */
|
||||
meshtastic_PortNum_SERIAL_APP = 64,
|
||||
/* STORE_FORWARD_APP (Work in Progress)
|
||||
Maintained by Jm Casler (MC Hamster) : jm@casler.org */
|
||||
Maintained by Jm Casler (MC Hamster) : jm@casler.org
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_STORE_FORWARD_APP = 65,
|
||||
/* Optional port for messages for the range test module. */
|
||||
/* Optional port for messages for the range test module.
|
||||
ENCODING: ASCII Plaintext */
|
||||
meshtastic_PortNum_RANGE_TEST_APP = 66,
|
||||
/* Provides a format to send and receive telemetry data from the Meshtastic network.
|
||||
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com */
|
||||
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_TELEMETRY_APP = 67,
|
||||
/* Experimental tools for estimating node position without a GPS
|
||||
Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
|
||||
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS */
|
||||
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS
|
||||
ENCODING: arrays of int64 fields */
|
||||
meshtastic_PortNum_ZPS_APP = 68,
|
||||
/* Used to let multiple instances of Linux native applications communicate
|
||||
as if they did using their LoRa chip.
|
||||
Maintained by GitHub user GUVWAF.
|
||||
Project files at https://github.com/GUVWAF/Meshtasticator */
|
||||
Project files at https://github.com/GUVWAF/Meshtasticator
|
||||
ENCODING: Protobuf (?) */
|
||||
meshtastic_PortNum_SIMULATOR_APP = 69,
|
||||
/* Provides a traceroute functionality to show the route a packet towards
|
||||
a certain destination would take on the mesh. */
|
||||
a certain destination would take on the mesh.
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_TRACEROUTE_APP = 70,
|
||||
/* Aggregates edge info for the network by sending out a list of each node's neighbors */
|
||||
/* Aggregates edge info for the network by sending out a list of each node's neighbors
|
||||
ENCODING: Protobuf */
|
||||
meshtastic_PortNum_NEIGHBORINFO_APP = 71,
|
||||
/* Private applications should use portnums >= 256.
|
||||
To simplify initial development and testing you can use "PRIVATE_APP"
|
||||
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */
|
||||
meshtastic_PortNum_PRIVATE_APP = 256,
|
||||
/* ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder */
|
||||
/* ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder
|
||||
ENCODING: libcotshrink */
|
||||
meshtastic_PortNum_ATAK_FORWARDER = 257,
|
||||
/* Currently we limit port nums to no higher than this value */
|
||||
meshtastic_PortNum_MAX = 511
|
||||
|
||||
@@ -402,7 +402,6 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
"href=/admin>admin</a>");
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
res->setHeader("Content-Encoding", "gzip");
|
||||
}
|
||||
@@ -438,7 +437,6 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
file.close();
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
LOG_ERROR("This should not have happened...\n");
|
||||
res->println("ERROR: This should not have happened...");
|
||||
@@ -467,7 +465,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
||||
// first semicolon, if one exists:
|
||||
size_t semicolonPos = contentType.find(";");
|
||||
if (semicolonPos != std::string::npos) {
|
||||
contentType = contentType.substr(0, semicolonPos);
|
||||
contentType.resize(semicolonPos);
|
||||
}
|
||||
|
||||
// Now, we can decide based on the content type:
|
||||
@@ -581,7 +579,6 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
res->setHeader("Content-Type", "application/json");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||
|
||||
} else {
|
||||
res->setHeader("Content-Type", "text/html");
|
||||
res->println("<pre>");
|
||||
@@ -857,4 +854,4 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
#define MAX_RX_TOPHONE 32
|
||||
|
||||
/// max number of nodes allowed in the mesh
|
||||
#define MAX_NUM_NODES (member_size(meshtastic_DeviceState, node_db) / member_size(meshtastic_DeviceState, node_db[0]))
|
||||
#define MAX_NUM_NODES (member_size(meshtastic_DeviceState, node_db_lite) / member_size(meshtastic_DeviceState, node_db_lite[0]))
|
||||
|
||||
/// Max number of channels allowed
|
||||
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
|
||||
|
||||
58
src/meshUtils.cpp
Normal file
58
src/meshUtils.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "meshUtils.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Find the first occurrence of find in s, where the search is limited to the
|
||||
* first slen characters of s.
|
||||
* -
|
||||
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
char *strnstr(const char *s, const char *find, size_t slen)
|
||||
{
|
||||
char c, sc;
|
||||
size_t len;
|
||||
|
||||
if ((c = *find++) != '\0') {
|
||||
len = strlen(find);
|
||||
do {
|
||||
do {
|
||||
if (slen-- < 1 || (sc = *s++) == '\0')
|
||||
return (NULL);
|
||||
} while (sc != c);
|
||||
if (len > slen)
|
||||
return (NULL);
|
||||
} while (strncmp(s, find, len) != 0);
|
||||
s--;
|
||||
}
|
||||
return ((char *)s);
|
||||
}
|
||||
@@ -4,4 +4,9 @@
|
||||
template <class T> constexpr const T &clamp(const T &v, const T &lo, const T &hi)
|
||||
{
|
||||
return (v < lo) ? lo : (hi < v) ? hi : v;
|
||||
}
|
||||
}
|
||||
|
||||
#if (defined(ARCH_PORTDUINO) && !defined(STRNSTR))
|
||||
#define STRNSTR
|
||||
char *strnstr(const char *s, const char *find, size_t slen);
|
||||
#endif
|
||||
@@ -368,6 +368,16 @@ void AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
||||
moduleConfig.has_remote_hardware = true;
|
||||
moduleConfig.remote_hardware = c.payload_variant.remote_hardware;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_neighbor_info_tag:
|
||||
LOG_INFO("Setting module config: Neighbor Info\n");
|
||||
moduleConfig.has_neighbor_info = true;
|
||||
moduleConfig.neighbor_info = c.payload_variant.neighbor_info;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_detection_sensor_tag:
|
||||
LOG_INFO("Setting module config: Detection Sensor\n");
|
||||
moduleConfig.has_detection_sensor = true;
|
||||
moduleConfig.detection_sensor = c.payload_variant.detection_sensor;
|
||||
break;
|
||||
}
|
||||
|
||||
saveChanges(SEGMENT_MODULECONFIG);
|
||||
@@ -503,6 +513,16 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
|
||||
res.get_module_config_response.payload_variant.remote_hardware = moduleConfig.remote_hardware;
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_NEIGHBORINFO_CONFIG:
|
||||
LOG_INFO("Getting module config: Neighbor Info\n");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
|
||||
res.get_module_config_response.payload_variant.neighbor_info = moduleConfig.neighbor_info;
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG:
|
||||
LOG_INFO("Getting module config: Detection Sensor\n");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
|
||||
res.get_module_config_response.payload_variant.detection_sensor = moduleConfig.detection_sensor;
|
||||
break;
|
||||
}
|
||||
|
||||
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
|
||||
@@ -663,4 +683,4 @@ AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_AP
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::adminChannel;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
#include "main.h" // for cardkb_found
|
||||
|
||||
#ifndef INPUTBROKER_MATRIX_TYPE
|
||||
#define INPUTBROKER_MATRIX_TYPE 0
|
||||
#endif
|
||||
|
||||
#ifdef OLED_RU
|
||||
#include "graphics/fonts/OLEDDisplayFontsRU.h"
|
||||
#endif
|
||||
@@ -18,7 +22,9 @@
|
||||
#include "graphics/fonts/OLEDDisplayFontsUA.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16
|
||||
#define FONT_MEDIUM ArialMT_Plain_24
|
||||
@@ -57,9 +63,10 @@ CannedMessageModule *cannedMessageModule;
|
||||
CannedMessageModule::CannedMessageModule()
|
||||
: SinglePortModule("canned", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("CannedMessageModule")
|
||||
{
|
||||
if (moduleConfig.canned_message.enabled) {
|
||||
if (moduleConfig.canned_message.enabled || CANNED_MESSAGE_MODULE_ENABLE) {
|
||||
this->loadProtoForModule();
|
||||
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address != CARDKB_ADDR)) {
|
||||
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address == 0x00) && !INPUTBROKER_MATRIX_TYPE &&
|
||||
!CANNED_MESSAGE_MODULE_ENABLE) {
|
||||
LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
|
||||
disable();
|
||||
@@ -134,12 +141,12 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
|
||||
bool validEvent = false;
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP)) {
|
||||
LOG_DEBUG("Canned message event UP\n");
|
||||
// LOG_DEBUG("Canned message event UP\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP;
|
||||
validEvent = true;
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN)) {
|
||||
LOG_DEBUG("Canned message event DOWN\n");
|
||||
// LOG_DEBUG("Canned message event DOWN\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN;
|
||||
validEvent = true;
|
||||
}
|
||||
@@ -163,13 +170,22 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
if ((event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
|
||||
LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
// LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
|
||||
// tweak for left/right events generated via trackball/touch with empty kbchar
|
||||
if (!event->kbchar) {
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
this->payload = 0xb4;
|
||||
this->destSelect = true;
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
this->payload = 0xb7;
|
||||
this->destSelect = true;
|
||||
}
|
||||
} else {
|
||||
// pass the pressed key
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(ANYKEY)) {
|
||||
LOG_DEBUG("Canned message event any key pressed\n");
|
||||
@@ -179,6 +195,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||
}
|
||||
// pass the pressed key
|
||||
// LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
@@ -208,9 +225,9 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
|
||||
p->want_ack = true;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
if (moduleConfig.canned_message.send_bell) {
|
||||
p->decoded.payload.bytes[p->decoded.payload.size - 1] = 7; // Bell character
|
||||
p->decoded.payload.bytes[p->decoded.payload.size] = '\0'; // Bell character
|
||||
if (moduleConfig.canned_message.send_bell && p->decoded.payload.size < meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
p->decoded.payload.bytes[p->decoded.payload.size] = 7; // Bell character
|
||||
p->decoded.payload.bytes[p->decoded.payload.size + 1] = '\0'; // Bell character
|
||||
p->decoded.payload.size++;
|
||||
}
|
||||
|
||||
@@ -221,11 +238,11 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
|
||||
|
||||
int32_t CannedMessageModule::runOnce()
|
||||
{
|
||||
if ((!moduleConfig.canned_message.enabled) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
return INT32_MAX;
|
||||
}
|
||||
LOG_DEBUG("Check status\n");
|
||||
// LOG_DEBUG("Check status\n");
|
||||
UIFrameEvent e = {false, true};
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
// TODO: might have some feedback of sendig state
|
||||
@@ -300,8 +317,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
}
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) {
|
||||
switch (this->payload) {
|
||||
case 0xb4: // left
|
||||
if (this->destSelect) {
|
||||
@@ -347,38 +363,50 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x08: // backspace
|
||||
if (this->freetext.length() > 0) {
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
|
||||
} else {
|
||||
this->freetext = this->freetext.substring(0, this->cursor - 1) +
|
||||
this->freetext.substring(this->cursor, this->freetext.length());
|
||||
}
|
||||
this->cursor--;
|
||||
}
|
||||
break;
|
||||
case 0x09: // tab
|
||||
if (this->destSelect) {
|
||||
this->destSelect = false;
|
||||
} else {
|
||||
this->destSelect = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext += this->payload;
|
||||
} else {
|
||||
this->freetext =
|
||||
this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
|
||||
}
|
||||
this->cursor += 1;
|
||||
if (this->freetext.length() > meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
this->cursor = meshtastic_Constants_DATA_PAYLOAD_LEN;
|
||||
this->freetext = this->freetext.substring(0, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
switch (this->payload) {
|
||||
case 0x08: // backspace
|
||||
if (this->freetext.length() > 0) {
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
|
||||
} else {
|
||||
this->freetext = this->freetext.substring(0, this->cursor - 1) +
|
||||
this->freetext.substring(this->cursor, this->freetext.length());
|
||||
}
|
||||
this->cursor--;
|
||||
}
|
||||
break;
|
||||
case 0x09: // tab
|
||||
if (this->destSelect) {
|
||||
this->destSelect = false;
|
||||
} else {
|
||||
this->destSelect = true;
|
||||
}
|
||||
break;
|
||||
case 0xb4: // left
|
||||
case 0xb7: // right
|
||||
// already handled above
|
||||
break;
|
||||
default:
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext += this->payload;
|
||||
} else {
|
||||
this->freetext =
|
||||
this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
|
||||
}
|
||||
this->cursor += 1;
|
||||
uint16_t maxChars = meshtastic_Constants_DATA_PAYLOAD_LEN - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||
if (this->freetext.length() > maxChars) {
|
||||
this->cursor = maxChars;
|
||||
this->freetext = this->freetext.substring(0, maxChars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->lastTouchMillis = millis();
|
||||
this->notifyObservers(&e);
|
||||
@@ -406,6 +434,11 @@ const char *CannedMessageModule::getNextMessage()
|
||||
{
|
||||
return this->messages[this->getNextIndex()];
|
||||
}
|
||||
const char *CannedMessageModule::getMessageByIndex(int index)
|
||||
{
|
||||
return (index >= 0 && index < this->messagesCount) ? this->messages[index] : "";
|
||||
}
|
||||
|
||||
const char *CannedMessageModule::getNodeName(NodeNum node)
|
||||
{
|
||||
if (node == NODENUM_BROADCAST) {
|
||||
@@ -422,7 +455,7 @@ const char *CannedMessageModule::getNodeName(NodeNum node)
|
||||
|
||||
bool CannedMessageModule::shouldDraw()
|
||||
{
|
||||
if (!moduleConfig.canned_message.enabled) {
|
||||
if (!moduleConfig.canned_message.enabled && !CANNED_MESSAGE_MODULE_ENABLE) {
|
||||
return false;
|
||||
}
|
||||
return (currentMessageIndex != -1) || (this->runState != CANNED_MESSAGE_RUN_STATE_INACTIVE);
|
||||
@@ -468,7 +501,9 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
// used chars right aligned
|
||||
snprintf(buffer, sizeof(buffer), "%d left", meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length());
|
||||
uint16_t charsLeft =
|
||||
meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length() - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||
snprintf(buffer, sizeof(buffer), "%d left", charsLeft);
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
|
||||
if (this->destSelect) {
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer) - 1, y + 0, buffer);
|
||||
@@ -482,12 +517,31 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
|
||||
int lines = (display->getHeight() / FONT_HEIGHT_SMALL) - 1;
|
||||
if (lines == 3) {
|
||||
// static (old) behavior for small displays
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
|
||||
} else {
|
||||
// use entire display height for larger displays
|
||||
int topMsg = (messagesCount > lines && currentMessageIndex >= lines - 1) ? currentMessageIndex - lines + 2 : 0;
|
||||
for (int i = 0; i < std::min(messagesCount, lines); i++) {
|
||||
if (i == currentMessageIndex - topMsg) {
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), x + display->getWidth(),
|
||||
y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
} else {
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1),
|
||||
cannedMessageModule->getMessageByIndex(topMsg + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,4 +650,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,10 @@ enum cannedMessageModuleRunState {
|
||||
*/
|
||||
#define CANNED_MESSAGE_MODULE_MESSAGES_SIZE 800
|
||||
|
||||
#ifndef CANNED_MESSAGE_MODULE_ENABLE
|
||||
#define CANNED_MESSAGE_MODULE_ENABLE 0
|
||||
#endif
|
||||
|
||||
class CannedMessageModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
|
||||
{
|
||||
CallbackObserver<CannedMessageModule, const InputEvent *> inputObserver =
|
||||
@@ -30,6 +34,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
const char *getCurrentMessage();
|
||||
const char *getPrevMessage();
|
||||
const char *getNextMessage();
|
||||
const char *getMessageByIndex(int index);
|
||||
const char *getNodeName(NodeNum node);
|
||||
bool shouldDraw();
|
||||
void eventUp();
|
||||
|
||||
102
src/modules/DetectionSensorModule.cpp
Normal file
102
src/modules/DetectionSensorModule.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "DetectionSensorModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
||||
DetectionSensorModule *detectionSensorModule;
|
||||
|
||||
#define GPIO_POLLING_INTERVAL 100
|
||||
#define DELAYED_INTERVAL 1000
|
||||
|
||||
int32_t DetectionSensorModule::runOnce()
|
||||
{
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
// moduleConfig.detection_sensor.enabled = true;
|
||||
// moduleConfig.detection_sensor.monitor_pin = 10; // WisBlock PIR IO6
|
||||
// moduleConfig.detection_sensor.monitor_pin = 21; // WisBlock RAK12013 Radar IO6
|
||||
// moduleConfig.detection_sensor.minimum_broadcast_secs = 30;
|
||||
// moduleConfig.detection_sensor.state_broadcast_secs = 120;
|
||||
// moduleConfig.detection_sensor.detection_triggered_high = true;
|
||||
// strcpy(moduleConfig.detection_sensor.name, "Motion");
|
||||
|
||||
if (moduleConfig.detection_sensor.enabled == false)
|
||||
return disable();
|
||||
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do some setup
|
||||
firstTime = false;
|
||||
if (moduleConfig.detection_sensor.monitor_pin > 0) {
|
||||
pinMode(moduleConfig.detection_sensor.monitor_pin, moduleConfig.detection_sensor.use_pullup ? INPUT_PULLUP : INPUT);
|
||||
} else {
|
||||
LOG_WARN("Detection Sensor Module: Set to enabled but no monitor pin is set. Disabling module...\n");
|
||||
return disable();
|
||||
}
|
||||
LOG_INFO("Detection Sensor Module: Initializing\n");
|
||||
|
||||
return DELAYED_INTERVAL;
|
||||
}
|
||||
|
||||
// LOG_DEBUG("Detection Sensor Module: Current pin state: %i\n", digitalRead(moduleConfig.detection_sensor.monitor_pin));
|
||||
|
||||
if ((millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs) &&
|
||||
hasDetectionEvent()) {
|
||||
sendDetectionMessage();
|
||||
return DELAYED_INTERVAL;
|
||||
}
|
||||
// Even if we haven't detected an event, broadcast our current state to the mesh on the scheduled interval as a sort
|
||||
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
|
||||
// change detections.
|
||||
else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
|
||||
(millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs)) {
|
||||
sendCurrentStateMessage();
|
||||
return DELAYED_INTERVAL;
|
||||
}
|
||||
return GPIO_POLLING_INTERVAL;
|
||||
}
|
||||
|
||||
void DetectionSensorModule::sendDetectionMessage()
|
||||
{
|
||||
LOG_DEBUG("Detected event observed. Sending message\n");
|
||||
char *message = new char[40];
|
||||
sprintf(message, "%s detected", moduleConfig.detection_sensor.name);
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
p->want_ack = false;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
if (moduleConfig.detection_sensor.send_bell && p->decoded.payload.size < meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
p->decoded.payload.bytes[p->decoded.payload.size] = 7; // Bell character
|
||||
p->decoded.payload.bytes[p->decoded.payload.size + 1] = '\0'; // Bell character
|
||||
p->decoded.payload.size++;
|
||||
}
|
||||
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
lastSentToMesh = millis();
|
||||
service.sendToMesh(p);
|
||||
delete[] message;
|
||||
}
|
||||
|
||||
void DetectionSensorModule::sendCurrentStateMessage()
|
||||
{
|
||||
char *message = new char[40];
|
||||
sprintf(message, "%s state: %i", moduleConfig.detection_sensor.name, hasDetectionEvent());
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
p->want_ack = false;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
lastSentToMesh = millis();
|
||||
service.sendToMesh(p);
|
||||
delete[] message;
|
||||
}
|
||||
|
||||
bool DetectionSensorModule::hasDetectionEvent()
|
||||
{
|
||||
bool currentState = digitalRead(moduleConfig.detection_sensor.monitor_pin);
|
||||
// LOG_DEBUG("Detection Sensor Module: Current state: %i\n", currentState);
|
||||
return moduleConfig.detection_sensor.detection_triggered_high ? currentState : !currentState;
|
||||
}
|
||||
23
src/modules/DetectionSensorModule.h
Normal file
23
src/modules/DetectionSensorModule.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "SinglePortModule.h"
|
||||
|
||||
class DetectionSensorModule : public SinglePortModule, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
DetectionSensorModule()
|
||||
: SinglePortModule("detection", meshtastic_PortNum_DETECTION_SENSOR_APP), OSThread("DetectionSensorModule")
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
bool firstTime = true;
|
||||
uint32_t lastSentToMesh = 0;
|
||||
void sendDetectionMessage();
|
||||
void sendCurrentStateMessage();
|
||||
bool hasDetectionEvent();
|
||||
};
|
||||
|
||||
extern DetectionSensorModule *detectionSensorModule;
|
||||
@@ -1,3 +1,18 @@
|
||||
/**
|
||||
* @file ExternalNotificationModule.cpp
|
||||
* @brief Implementation of the ExternalNotificationModule class.
|
||||
*
|
||||
* This file contains the implementation of the ExternalNotificationModule class, which is responsible for handling external
|
||||
* notifications such as vibration, buzzer, and LED lights. The class provides methods to turn on and off the external
|
||||
* notification outputs and to play ringtones using PWM buzzer. It also includes default configurations and a runOnce() method to
|
||||
* handle the module's behavior.
|
||||
*
|
||||
* Documentation:
|
||||
* https://meshtastic.org/docs/settings/moduleconfig/external-notification
|
||||
*
|
||||
* @author Jm Casler & Meshtastic Team
|
||||
* @date [Insert Date]
|
||||
*/
|
||||
#include "ExternalNotificationModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -113,6 +128,16 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
bool ExternalNotificationModule::wantPacket(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
return MeshService::isTextPayload(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the external notification on for the specified index.
|
||||
*
|
||||
* @param index The index of the external notification to turn on.
|
||||
*/
|
||||
void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||
{
|
||||
externalCurrentState[index] = 1;
|
||||
@@ -192,8 +217,8 @@ void ExternalNotificationModule::stopNow()
|
||||
}
|
||||
|
||||
ExternalNotificationModule::ExternalNotificationModule()
|
||||
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread(
|
||||
"ExternalNotificationModule")
|
||||
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP),
|
||||
concurrency::OSThread("ExternalNotificationModule")
|
||||
{
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
|
||||
@@ -52,6 +52,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override;
|
||||
|
||||
bool isNagging = false;
|
||||
|
||||
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
||||
@@ -59,4 +61,4 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
meshtastic_AdminMessage *response) override;
|
||||
};
|
||||
|
||||
extern ExternalNotificationModule *externalNotificationModule;
|
||||
extern ExternalNotificationModule *externalNotificationModule;
|
||||
@@ -1,10 +1,14 @@
|
||||
#include "configuration.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#include "input/kbMatrixImpl.h"
|
||||
#include "modules/AdminModule.h"
|
||||
#include "modules/CannedMessageModule.h"
|
||||
#include "modules/DetectionSensorModule.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include "modules/NodeInfoModule.h"
|
||||
#include "modules/PositionModule.h"
|
||||
#include "modules/RemoteHardwareModule.h"
|
||||
@@ -24,7 +28,7 @@
|
||||
#include "modules/esp32/AudioModule.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/RangeTestModule.h"
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
@@ -46,6 +50,8 @@ void setupModules()
|
||||
waypointModule = new WaypointModule();
|
||||
textMessageModule = new TextMessageModule();
|
||||
traceRouteModule = new TraceRouteModule();
|
||||
neighborInfoModule = new NeighborInfoModule();
|
||||
detectionSensorModule = new DetectionSensorModule();
|
||||
|
||||
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
|
||||
// to a global variable.
|
||||
@@ -59,6 +65,14 @@ void setupModules()
|
||||
upDownInterruptImpl1->init();
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
kbMatrixImpl = new KbMatrixImpl();
|
||||
kbMatrixImpl->init();
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
#endif // HAS_BUTTON
|
||||
#if HAS_TRACKBALL
|
||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||
trackballInterruptImpl1->init();
|
||||
#endif
|
||||
#if HAS_SCREEN
|
||||
cannedMessageModule = new CannedMessageModule();
|
||||
@@ -81,15 +95,18 @@ void setupModules()
|
||||
|
||||
storeForwardModule = new StoreForwardModule();
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
|
||||
externalNotificationModule = new ExternalNotificationModule();
|
||||
new RangeTestModule();
|
||||
#endif
|
||||
} else {
|
||||
adminModule = new AdminModule();
|
||||
#if HAS_TELEMETRY
|
||||
new DeviceTelemetryModule();
|
||||
#endif
|
||||
traceRouteModule = new TraceRouteModule();
|
||||
}
|
||||
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra
|
||||
// acks
|
||||
routingModule = new RoutingModule();
|
||||
}
|
||||
}
|
||||
310
src/modules/NeighborInfoModule.cpp
Normal file
310
src/modules/NeighborInfoModule.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
#include "NeighborInfoModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
|
||||
#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options
|
||||
NeighborInfoModule *neighborInfoModule;
|
||||
|
||||
static const char *neighborInfoConfigFile = "/prefs/neighbors.proto";
|
||||
|
||||
/*
|
||||
Prints a single neighbor info packet and associated neighbors
|
||||
Uses LOG_DEBUG, which equates to Console.log
|
||||
NOTE: For debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np)
|
||||
{
|
||||
LOG_DEBUG("%s NEIGHBORINFO PACKET from Node 0x%x to Node 0x%x (last sent by 0x%x)\n", header, np->node_id,
|
||||
nodeDB.getNodeNum(), np->last_sent_by_id);
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("Packet contains %d neighbors\n", np->neighbors_count);
|
||||
for (int i = 0; i < np->neighbors_count; i++) {
|
||||
LOG_DEBUG("Neighbor %d: node_id=0x%x, snr=%.2f\n", i, np->neighbors[i].node_id, np->neighbors[i].snr);
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
/*
|
||||
Prints the nodeDB nodes so we can see whose nodeInfo we have
|
||||
NOTE: for debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNodeDBNodes(const char *header)
|
||||
{
|
||||
int num_nodes = nodeDB.getNumMeshNodes();
|
||||
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("DB contains %d nodes\n", num_nodes);
|
||||
for (int i = 0; i < num_nodes; i++) {
|
||||
const meshtastic_NodeInfoLite *dbEntry = nodeDB.getMeshNodeByIndex(i);
|
||||
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->num, dbEntry->snr);
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
Prints the nodeDB neighbors
|
||||
NOTE: for debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNodeDBNeighbors(const char *header)
|
||||
{
|
||||
int num_neighbors = getNumNeighbors();
|
||||
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("DB contains %d neighbors\n", num_neighbors);
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
Prints the nodeDB with selectors for the neighbors we've chosen to send (inefficiently)
|
||||
Uses LOG_DEBUG, which equates to Console.log
|
||||
NOTE: For debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np)
|
||||
{
|
||||
int num_neighbors = getNumNeighbors();
|
||||
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
|
||||
LOG_DEBUG("----------------\n");
|
||||
LOG_DEBUG("Selected %d neighbors of %d DB neighbors\n", np->neighbors_count, num_neighbors);
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
bool chosen = false;
|
||||
for (int j = 0; j < np->neighbors_count; j++) {
|
||||
if (np->neighbors[j].node_id == dbEntry->node_id) {
|
||||
chosen = true;
|
||||
}
|
||||
}
|
||||
if (!chosen) {
|
||||
LOG_DEBUG(" Node %d: neighbor=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
||||
} else {
|
||||
LOG_DEBUG("---> Node %d: neighbor=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("----------------\n");
|
||||
}
|
||||
|
||||
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
|
||||
NeighborInfoModule::NeighborInfoModule()
|
||||
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
||||
concurrency::OSThread("NeighborInfoModule"), neighbors(neighborState.neighbors),
|
||||
numNeighbors(&neighborState.neighbors_count)
|
||||
{
|
||||
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
|
||||
|
||||
if (moduleConfig.neighbor_info.enabled) {
|
||||
this->loadProtoForModule();
|
||||
setIntervalFromNow(35 * 1000);
|
||||
} else {
|
||||
LOG_DEBUG("NeighborInfoModule is disabled\n");
|
||||
neighborState = meshtastic_NeighborInfo_init_zero;
|
||||
disable();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
||||
Assumes that the neighborInfo packet has been allocated
|
||||
@returns the number of entries collected
|
||||
*/
|
||||
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
||||
{
|
||||
uint my_node_id = nodeDB.getNodeNum();
|
||||
neighborInfo->node_id = my_node_id;
|
||||
neighborInfo->last_sent_by_id = my_node_id;
|
||||
neighborInfo->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||
|
||||
int num_neighbors = cleanUpNeighbors();
|
||||
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (dbEntry->node_id != my_node_id)) {
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = dbEntry->node_id;
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = dbEntry->snr;
|
||||
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
|
||||
// the mesh
|
||||
neighborInfo->neighbors_count++;
|
||||
}
|
||||
}
|
||||
printNodeDBNodes("DBSTATE");
|
||||
printNodeDBNeighbors("NEIGHBORS");
|
||||
printNodeDBSelection("COLLECTED", neighborInfo);
|
||||
return neighborInfo->neighbors_count;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
@returns new number of neighbors
|
||||
*/
|
||||
size_t NeighborInfoModule::cleanUpNeighbors()
|
||||
{
|
||||
uint32_t now = getTime();
|
||||
int num_neighbors = getNumNeighbors();
|
||||
NodeNum my_node_id = nodeDB.getNodeNum();
|
||||
|
||||
// Find neighbors to remove
|
||||
std::vector<int> indices_to_remove;
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
||||
if ((now - dbEntry->last_rx_time > dbEntry->node_broadcast_interval_secs * 2) && (dbEntry->node_id != my_node_id)) {
|
||||
indices_to_remove.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the neighbor list
|
||||
for (uint i = 0; i < indices_to_remove.size(); i++) {
|
||||
int index = indices_to_remove[i];
|
||||
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", neighbors[index].node_id);
|
||||
for (int j = index; j < num_neighbors - 1; j++) {
|
||||
neighbors[j] = neighbors[j + 1];
|
||||
}
|
||||
(*numNeighbors)--;
|
||||
}
|
||||
|
||||
// Save the neighbor list if we removed any neighbors
|
||||
if (indices_to_remove.size() > 0) {
|
||||
saveProtoForModule();
|
||||
}
|
||||
|
||||
return *numNeighbors;
|
||||
}
|
||||
|
||||
/* Send neighbor info to the mesh */
|
||||
void NeighborInfoModule::sendNeighborInfo(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_NeighborInfo neighborInfo = meshtastic_NeighborInfo_init_zero;
|
||||
collectNeighborInfo(&neighborInfo);
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(neighborInfo);
|
||||
// send regardless of whether or not we have neighbors in our DB,
|
||||
// because we want to get neighbors for the next cycle
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
printNeighborInfo("SENDING", &neighborInfo);
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Encompasses the full construction and sending packet to mesh
|
||||
Will be used for broadcast.
|
||||
*/
|
||||
int32_t NeighborInfoModule::runOnce()
|
||||
{
|
||||
bool requestReplies = false;
|
||||
sendNeighborInfo(NODENUM_BROADCAST, requestReplies);
|
||||
return getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs);
|
||||
}
|
||||
|
||||
/*
|
||||
Collect a recieved neighbor info packet from another node
|
||||
Pass it to an upper client; do not persist this data on the mesh
|
||||
*/
|
||||
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
|
||||
{
|
||||
printNeighborInfo("RECEIVED", np);
|
||||
updateNeighbors(mp, np);
|
||||
// Allow others to handle this packet
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Copy the content of a current NeighborInfo packet into a new one and update the last_sent_by_id to our NodeNum
|
||||
*/
|
||||
void NeighborInfoModule::updateLastSentById(meshtastic_MeshPacket *p)
|
||||
{
|
||||
auto &incoming = p->decoded;
|
||||
meshtastic_NeighborInfo scratch;
|
||||
meshtastic_NeighborInfo *updated = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, &meshtastic_NeighborInfo_msg, &scratch);
|
||||
updated = &scratch;
|
||||
|
||||
updated->last_sent_by_id = nodeDB.getNodeNum();
|
||||
|
||||
// Set updated last_sent_by_id to the payload of the to be flooded packet
|
||||
p->decoded.payload.size =
|
||||
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_NeighborInfo_msg, updated);
|
||||
}
|
||||
|
||||
void NeighborInfoModule::resetNeighbors()
|
||||
{
|
||||
*numNeighbors = 0;
|
||||
neighborState.neighbors_count = 0;
|
||||
memset(neighborState.neighbors, 0, sizeof(neighborState.neighbors));
|
||||
saveProtoForModule();
|
||||
}
|
||||
|
||||
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
||||
{
|
||||
// The last sent ID will be 0 if the packet is from the phone, which we don't count as
|
||||
// an edge. So we assume that if it's zero, then this packet is from our node.
|
||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
||||
getOrCreateNeighbor(mp.from, np->last_sent_by_id, np->node_broadcast_interval_secs, mp.rx_snr);
|
||||
}
|
||||
}
|
||||
|
||||
meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSender, NodeNum n,
|
||||
uint32_t node_broadcast_interval_secs, float snr)
|
||||
{
|
||||
// our node and the phone are the same node (not neighbors)
|
||||
if (n == 0) {
|
||||
n = nodeDB.getNodeNum();
|
||||
}
|
||||
// look for one in the existing list
|
||||
for (int i = 0; i < (*numNeighbors); i++) {
|
||||
meshtastic_Neighbor *nbr = &neighbors[i];
|
||||
if (nbr->node_id == n) {
|
||||
// if found, update it
|
||||
nbr->snr = snr;
|
||||
nbr->last_rx_time = getTime();
|
||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||
if (originalSender == n)
|
||||
nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
saveProtoForModule(); // Save the updated neighbor
|
||||
return nbr;
|
||||
}
|
||||
}
|
||||
// otherwise, allocate one and assign data to it
|
||||
// TODO: max memory for the database should take neighbors into account, but currently doesn't
|
||||
if (*numNeighbors < MAX_NUM_NEIGHBORS) {
|
||||
(*numNeighbors)++;
|
||||
}
|
||||
meshtastic_Neighbor *new_nbr = &neighbors[((*numNeighbors) - 1)];
|
||||
new_nbr->node_id = n;
|
||||
new_nbr->snr = snr;
|
||||
new_nbr->last_rx_time = getTime();
|
||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||
if (originalSender == n)
|
||||
new_nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
saveProtoForModule(); // Save the new neighbor
|
||||
return new_nbr;
|
||||
}
|
||||
|
||||
void NeighborInfoModule::loadProtoForModule()
|
||||
{
|
||||
if (!nodeDB.loadProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, sizeof(meshtastic_NeighborInfo),
|
||||
&meshtastic_NeighborInfo_msg, &neighborState)) {
|
||||
neighborState = meshtastic_NeighborInfo_init_zero;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Save the module config to file.
|
||||
*
|
||||
* @return true On success.
|
||||
* @return false On error.
|
||||
*/
|
||||
bool NeighborInfoModule::saveProtoForModule()
|
||||
{
|
||||
bool okay = true;
|
||||
|
||||
#ifdef FS
|
||||
FS.mkdir("/prefs");
|
||||
#endif
|
||||
|
||||
okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState);
|
||||
|
||||
return okay;
|
||||
}
|
||||
84
src/modules/NeighborInfoModule.h
Normal file
84
src/modules/NeighborInfoModule.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
#include "ProtobufModule.h"
|
||||
|
||||
/*
|
||||
* Neighborinfo module for sending info on each node's 0-hop neighbors to the mesh
|
||||
*/
|
||||
class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread
|
||||
{
|
||||
meshtastic_Neighbor *neighbors;
|
||||
pb_size_t *numNeighbors;
|
||||
|
||||
public:
|
||||
/*
|
||||
* Expose the constructor
|
||||
*/
|
||||
NeighborInfoModule();
|
||||
|
||||
/* Reset neighbor info after clearing nodeDB*/
|
||||
void resetNeighbors();
|
||||
|
||||
bool saveProtoForModule();
|
||||
|
||||
// Let FloodingRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet
|
||||
friend class FloodingRouter;
|
||||
|
||||
protected:
|
||||
// Note: this holds our local info.
|
||||
meshtastic_NeighborInfo neighborState;
|
||||
|
||||
/*
|
||||
* Called to handle a particular incoming message
|
||||
* @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override;
|
||||
|
||||
/*
|
||||
* Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
||||
* @return the number of entries collected
|
||||
*/
|
||||
uint32_t collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo);
|
||||
|
||||
/*
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
@returns new number of neighbors
|
||||
*/
|
||||
size_t cleanUpNeighbors();
|
||||
|
||||
/* Allocate a new NeighborInfo packet */
|
||||
meshtastic_NeighborInfo *allocateNeighborInfoPacket();
|
||||
|
||||
// Find a neighbor in our DB, create an empty neighbor if missing
|
||||
meshtastic_Neighbor *getOrCreateNeighbor(NodeNum originalSender, NodeNum n, uint32_t node_broadcast_interval_secs, float snr);
|
||||
|
||||
/*
|
||||
* Send info on our node's neighbors into the mesh
|
||||
*/
|
||||
void sendNeighborInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
size_t getNumNeighbors() { return *numNeighbors; }
|
||||
|
||||
meshtastic_Neighbor *getNeighborByIndex(size_t x)
|
||||
{
|
||||
assert(x < *numNeighbors);
|
||||
return &neighbors[x];
|
||||
}
|
||||
|
||||
/* update neighbors with subpacket sniffed from network */
|
||||
void updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np);
|
||||
|
||||
/* update a NeighborInfo packet with our NodeNum as last_sent_by_id */
|
||||
void updateLastSentById(meshtastic_MeshPacket *p);
|
||||
|
||||
void loadProtoForModule();
|
||||
|
||||
/* Does our periodic broadcast */
|
||||
int32_t runOnce() override;
|
||||
|
||||
/* These are for debugging only */
|
||||
void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
|
||||
void printNodeDBNodes(const char *header);
|
||||
void printNodeDBNeighbors(const char *header);
|
||||
void printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np);
|
||||
};
|
||||
extern NeighborInfoModule *neighborInfoModule;
|
||||
@@ -11,8 +11,8 @@
|
||||
PositionModule *positionModule;
|
||||
|
||||
PositionModule::PositionModule()
|
||||
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg), concurrency::OSThread(
|
||||
"PositionModule")
|
||||
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg),
|
||||
concurrency::OSThread("PositionModule")
|
||||
{
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
|
||||
@@ -52,11 +52,22 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
|
||||
nodeDB.updatePosition(getFrom(&mp), p);
|
||||
|
||||
// Only respond to location requests on the channel where we broadcast location.
|
||||
if (channels.getByIndex(mp.channel).role == meshtastic_Channel_Role_PRIMARY) {
|
||||
ignoreRequest = false;
|
||||
} else {
|
||||
ignoreRequest = true;
|
||||
}
|
||||
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *PositionModule::allocReply()
|
||||
{
|
||||
if (ignoreRequest) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *node = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
assert(node->has_position);
|
||||
|
||||
@@ -131,6 +142,11 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
|
||||
service.cancelSending(prevPacketId);
|
||||
|
||||
meshtastic_MeshPacket *p = allocReply();
|
||||
if (p == nullptr) {
|
||||
LOG_WARN("allocReply returned a nullptr");
|
||||
return;
|
||||
}
|
||||
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER)
|
||||
@@ -174,7 +190,7 @@ int32_t PositionModule::runOnce()
|
||||
} else if (config.position.position_broadcast_smart_enabled) {
|
||||
// Only send packets if the channel is less than 25% utilized or we're a tracker.
|
||||
if (airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) {
|
||||
meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
|
||||
if (hasValidPosition(node2)) {
|
||||
// The minimum distance to travel before we are able to send a new position packet.
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @file RangeTestModule.cpp
|
||||
* @brief Implementation of the RangeTestModule class and RangeTestModuleRadio class.
|
||||
*
|
||||
* As a sender, this module sends packets every n seconds with an incremented PacketID.
|
||||
* As a receiver, this module receives packets from multiple senders and saves them to the Filesystem.
|
||||
*
|
||||
* The RangeTestModule class is an OSThread that runs the module.
|
||||
* The RangeTestModuleRadio class handles sending and receiving packets.
|
||||
*/
|
||||
#include "RangeTestModule.h"
|
||||
#include "FSCommon.h"
|
||||
#include "MeshService.h"
|
||||
@@ -10,11 +20,6 @@
|
||||
#include "gps/GeoCoord.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
/*
|
||||
As a sender, I can send packets every n seconds. These packets include an incremented PacketID.
|
||||
As a receiver, I can receive packets from multiple senders. These packets can be saved to the Filesystem.
|
||||
*/
|
||||
|
||||
RangeTestModule *rangeTestModule;
|
||||
RangeTestModuleRadio *rangeTestModuleRadio;
|
||||
|
||||
@@ -97,6 +102,12 @@ int32_t RangeTestModule::runOnce()
|
||||
return disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a payload to a specified destination node.
|
||||
*
|
||||
* @param dest The destination node number.
|
||||
* @param wantReplies Whether or not to request replies from the destination node.
|
||||
*/
|
||||
void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
|
||||
@@ -29,7 +29,7 @@ class RangeTestModuleRadio : public SinglePortModule
|
||||
uint32_t lastRxID = 0;
|
||||
|
||||
public:
|
||||
RangeTestModuleRadio() : SinglePortModule("RangeTestModuleRadio", meshtastic_PortNum_TEXT_MESSAGE_APP)
|
||||
RangeTestModuleRadio() : SinglePortModule("RangeTestModuleRadio", meshtastic_PortNum_RANGE_TEST_APP)
|
||||
{
|
||||
loopbackOk = true; // Allow locally generated messages to loop back to the client
|
||||
}
|
||||
|
||||
@@ -86,7 +86,13 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
|
||||
}
|
||||
}
|
||||
|
||||
// For the serial2 port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
/**
|
||||
* @brief Checks if the serial connection is established.
|
||||
*
|
||||
* @return true if the serial connection is established, false otherwise.
|
||||
*
|
||||
* For the serial2 port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
*/
|
||||
bool SerialModule::checkIsConnected()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
@@ -191,6 +197,11 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new mesh packet for use as a reply to a received packet.
|
||||
*
|
||||
* @return A pointer to the newly allocated mesh packet.
|
||||
*/
|
||||
meshtastic_MeshPacket *SerialModuleRadio::allocReply()
|
||||
{
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
@@ -198,9 +209,15 @@ meshtastic_MeshPacket *SerialModuleRadio::allocReply()
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a payload to a specified destination node.
|
||||
*
|
||||
* @param dest The destination node number.
|
||||
* @param wantReplies Whether or not to request replies from the destination node.
|
||||
*/
|
||||
void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_Channel *ch = (boundChannel != NULL) ? &channels.getByName(boundChannel) : NULL;
|
||||
const meshtastic_Channel *ch = (boundChannel != NULL) ? &channels.getByName(boundChannel) : NULL;
|
||||
meshtastic_MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
if (ch != NULL) {
|
||||
@@ -216,6 +233,12 @@ void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a received mesh packet.
|
||||
*
|
||||
* @param mp The received mesh packet.
|
||||
* @return The processed message.
|
||||
*/
|
||||
ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
if (moduleConfig.serial.enabled) {
|
||||
@@ -249,7 +272,7 @@ ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp
|
||||
|
||||
if (moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
|
||||
moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
|
||||
serialPrint->printf("%s", p.payload.bytes);
|
||||
serialPrint->write(p.payload.bytes, p.payload.size);
|
||||
} else if (moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
|
||||
String sender = (node && node->has_user) ? node->user.short_name : "???";
|
||||
@@ -277,6 +300,11 @@ ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the baud rate of the serial module from the module configuration.
|
||||
*
|
||||
* @return uint32_t The baud rate of the serial module.
|
||||
*/
|
||||
uint32_t SerialModule::getBaudRate()
|
||||
{
|
||||
if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_110) {
|
||||
|
||||
@@ -17,7 +17,8 @@ int32_t DeviceTelemetryModule::runOnce()
|
||||
uint32_t now = millis();
|
||||
if (((lastSentToMesh == 0) ||
|
||||
((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) &&
|
||||
airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil()) {
|
||||
airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil() &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
sendTelemetry();
|
||||
lastSentToMesh = now;
|
||||
} else if (service.isToPhoneQueueEmpty()) {
|
||||
@@ -30,6 +31,10 @@ int32_t DeviceTelemetryModule::runOnce()
|
||||
|
||||
bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
{
|
||||
// Don't worry about storing telemetry in NodeDB if we're a repeater
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
|
||||
return false;
|
||||
|
||||
if (t->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||
#ifdef DEBUG_PORT
|
||||
const char *sender = getSenderShortName(mp);
|
||||
@@ -43,7 +48,19 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
meshtastic_MeshPacket *DeviceTelemetryModule::allocReply()
|
||||
{
|
||||
if (ignoreRequest) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_INFO("Device telemetry replying to request\n");
|
||||
|
||||
meshtastic_Telemetry telemetry = getDeviceTelemetry();
|
||||
return allocDataProtobuf(telemetry);
|
||||
}
|
||||
|
||||
meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry()
|
||||
{
|
||||
meshtastic_Telemetry t;
|
||||
|
||||
@@ -60,16 +77,22 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
t.variant.device_metrics.channel_utilization = airTime->channelUtilizationPercent();
|
||||
t.variant.device_metrics.voltage = powerStatus->getBatteryVoltageMv() / 1000.0;
|
||||
|
||||
LOG_INFO("(Sending): air_util_tx=%f, channel_utilization=%f, battery_level=%i, voltage=%f\n",
|
||||
t.variant.device_metrics.air_util_tx, t.variant.device_metrics.channel_utilization,
|
||||
t.variant.device_metrics.battery_level, t.variant.device_metrics.voltage);
|
||||
return t;
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(t);
|
||||
bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
{
|
||||
meshtastic_Telemetry telemetry = getDeviceTelemetry();
|
||||
LOG_INFO("(Sending): air_util_tx=%f, channel_utilization=%f, battery_level=%i, voltage=%f\n",
|
||||
telemetry.variant.device_metrics.air_util_tx, telemetry.variant.device_metrics.channel_utilization,
|
||||
telemetry.variant.device_metrics.battery_level, telemetry.variant.device_metrics.voltage);
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(telemetry);
|
||||
p->to = dest;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_MIN;
|
||||
|
||||
nodeDB.updateTelemetry(nodeDB.getNodeNum(), t, RX_SRC_LOCAL);
|
||||
nodeDB.updateTelemetry(nodeDB.getNodeNum(), telemetry, RX_SRC_LOCAL);
|
||||
if (phoneOnly) {
|
||||
LOG_INFO("Sending packet to phone\n");
|
||||
service.sendToPhone(p);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user