mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-28 05:30:30 +00:00
Compare commits
361 Commits
v1.2.52.b6
...
v1.3.3.2fe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fe124eb17 | ||
|
|
a450aac3b5 | ||
|
|
958f20da1a | ||
|
|
ef4c01f4ea | ||
|
|
97c76cde3c | ||
|
|
2ab0548dda | ||
|
|
75bf2cc9c6 | ||
|
|
ee533b2d5c | ||
|
|
52960f5fa2 | ||
|
|
5c281154fd | ||
|
|
2c7b3acbb9 | ||
|
|
cf928fca93 | ||
|
|
8eaaf842ab | ||
|
|
09edd7f89b | ||
|
|
556fc6210d | ||
|
|
4d8c0c11dc | ||
|
|
950b54aaba | ||
|
|
4b87a82eb3 | ||
|
|
2fa8f45d74 | ||
|
|
4209fc8b2c | ||
|
|
6d4d2bb6fa | ||
|
|
32ef354c22 | ||
|
|
a0395c1027 | ||
|
|
1f43132b52 | ||
|
|
ac8ba706f0 | ||
|
|
ca4c1c9d7c | ||
|
|
7b8746d596 | ||
|
|
91b0fcb257 | ||
|
|
768c26bb1b | ||
|
|
e5e13d78c3 | ||
|
|
a2eb148c50 | ||
|
|
33ed9476f8 | ||
|
|
92d5dedc63 | ||
|
|
10fefe7c7b | ||
|
|
92ffbca339 | ||
|
|
7c868c78cc | ||
|
|
3f2baeb56e | ||
|
|
ebba628736 | ||
|
|
2a02b4594f | ||
|
|
1e689b86b5 | ||
|
|
e53abbfb2b | ||
|
|
6f086bd3ba | ||
|
|
3c5e49d8f4 | ||
|
|
7a5ae40289 | ||
|
|
a83cfffd3a | ||
|
|
031b3665f8 | ||
|
|
206ae4e2b8 | ||
|
|
24556f2803 | ||
|
|
ffa7a36a03 | ||
|
|
ba7644e376 | ||
|
|
ebc9fef222 | ||
|
|
dee577cb5c | ||
|
|
ed5dea9f85 | ||
|
|
eeacb280d1 | ||
|
|
bc27dbde98 | ||
|
|
9b1bf7787c | ||
|
|
71bf9de638 | ||
|
|
3a04a0ee7a | ||
|
|
e218740488 | ||
|
|
86e767eec2 | ||
|
|
d57704b3bd | ||
|
|
218a208ab7 | ||
|
|
c5c12bcc6b | ||
|
|
0e686e4645 | ||
|
|
9050fe7f90 | ||
|
|
c511fa2fe6 | ||
|
|
9b44d2e999 | ||
|
|
01a86133ea | ||
|
|
338c30fe9a | ||
|
|
ac43a1b182 | ||
|
|
5bff62e428 | ||
|
|
a0f80c1a2a | ||
|
|
f9bcddafef | ||
|
|
a25beff241 | ||
|
|
529707489a | ||
|
|
ceccbd3ef2 | ||
|
|
59ce0c7d09 | ||
|
|
f2a31cc678 | ||
|
|
c97541d4fc | ||
|
|
fc54f2f63d | ||
|
|
c3cee236bd | ||
|
|
c5a8cc6d3f | ||
|
|
2e402a726b | ||
|
|
ca8598f8b7 | ||
|
|
b6d7eadea3 | ||
|
|
cd9def6850 | ||
|
|
060eac7ab9 | ||
|
|
d95d874258 | ||
|
|
e52f94820e | ||
|
|
31f4ec5d6c | ||
|
|
bb15ed903d | ||
|
|
ef2bc2b9fc | ||
|
|
972c2bb329 | ||
|
|
54ff8f2db3 | ||
|
|
a36889abba | ||
|
|
eb66ba2510 | ||
|
|
1e6e3805ad | ||
|
|
0133186f70 | ||
|
|
b15ef2749f | ||
|
|
7b2042f391 | ||
|
|
3d4fc63ecc | ||
|
|
3fdd425634 | ||
|
|
d416f28341 | ||
|
|
06064d92cd | ||
|
|
837c0e3717 | ||
|
|
389a8f1401 | ||
|
|
d32989cd7e | ||
|
|
e969e83037 | ||
|
|
57d824cf5d | ||
|
|
e34190b497 | ||
|
|
701668804a | ||
|
|
a7aa82e732 | ||
|
|
1075b95f79 | ||
|
|
29e70a80c6 | ||
|
|
8303500b74 | ||
|
|
e7e001c159 | ||
|
|
54f062e94d | ||
|
|
717491752b | ||
|
|
9cdc6ae860 | ||
|
|
4941fd30f7 | ||
|
|
5ddd280f92 | ||
|
|
3a621ef262 | ||
|
|
0c946609d5 | ||
|
|
554729dab2 | ||
|
|
ae6d0686bd | ||
|
|
57bbd912b1 | ||
|
|
6befed1176 | ||
|
|
1ba7f009dd | ||
|
|
eae8720068 | ||
|
|
18e95e6bb4 | ||
|
|
01e86512aa | ||
|
|
9fda734743 | ||
|
|
04d16b82ba | ||
|
|
4206982572 | ||
|
|
b99d793e23 | ||
|
|
71d5e6c478 | ||
|
|
111d7ecd5e | ||
|
|
1de086819c | ||
|
|
af1804ea62 | ||
|
|
fe87682d69 | ||
|
|
96b5537217 | ||
|
|
449926cff9 | ||
|
|
d4e5a3c67c | ||
|
|
2428ca09fc | ||
|
|
346712fbf3 | ||
|
|
a1ad1e7973 | ||
|
|
806a61251b | ||
|
|
34eee247e9 | ||
|
|
ee95594f74 | ||
|
|
7f3ad672b8 | ||
|
|
7cda49aba5 | ||
|
|
8e9b852faa | ||
|
|
6b4907e841 | ||
|
|
1808e9b3d8 | ||
|
|
1dd53eeaf5 | ||
|
|
892d9a34c7 | ||
|
|
ab96579904 | ||
|
|
3f83acdbef | ||
|
|
9db7c62a49 | ||
|
|
d79dc631f1 | ||
|
|
7ea6babb7f | ||
|
|
0b4b901504 | ||
|
|
cc7b5cf136 | ||
|
|
e3df4fe4b4 | ||
|
|
288f2be8ea | ||
|
|
c867af8522 | ||
|
|
856f2f9589 | ||
|
|
e649bc84e1 | ||
|
|
bbcd59ec7b | ||
|
|
e11fd593ae | ||
|
|
868af9dd6b | ||
|
|
10800a6914 | ||
|
|
e567fe7322 | ||
|
|
365120e9c2 | ||
|
|
b21b7de04b | ||
|
|
dd31a829fb | ||
|
|
9a505c27fa | ||
|
|
ed9cd7b03d | ||
|
|
66413d8b7f | ||
|
|
e4fe2c159a | ||
|
|
f5e0718052 | ||
|
|
64ff48c4a5 | ||
|
|
50969c4e42 | ||
|
|
5288f1846a | ||
|
|
c545155b03 | ||
|
|
a4e9fca80c | ||
|
|
3611293a98 | ||
|
|
dc7f376778 | ||
|
|
ff2cad9cac | ||
|
|
b781fb613c | ||
|
|
0a1125d7e4 | ||
|
|
ed2de3b885 | ||
|
|
19c1f9fa59 | ||
|
|
266d6ad205 | ||
|
|
66cd824437 | ||
|
|
e2db4f6927 | ||
|
|
56fb141ed0 | ||
|
|
e8e209be25 | ||
|
|
c278a0e299 | ||
|
|
fbc25c3a13 | ||
|
|
b7f04f4c91 | ||
|
|
d5377a0f19 | ||
|
|
dafc1092aa | ||
|
|
477b666998 | ||
|
|
dbcd720391 | ||
|
|
59c2bcd978 | ||
|
|
aea6675e64 | ||
|
|
8bff696bef | ||
|
|
da0ec09bf4 | ||
|
|
2c99020037 | ||
|
|
14419cbd02 | ||
|
|
1bfa6839e2 | ||
|
|
a61676504f | ||
|
|
f4d3de086a | ||
|
|
af249da1a3 | ||
|
|
7613c7bf83 | ||
|
|
e4608e0a10 | ||
|
|
d26549c7c2 | ||
|
|
697d52b9bd | ||
|
|
7a9450b250 | ||
|
|
6d372743f5 | ||
|
|
c2b309195d | ||
|
|
3c7670186a | ||
|
|
b51be320dd | ||
|
|
409ad9c2c3 | ||
|
|
eaa5252cdb | ||
|
|
3d718f45d5 | ||
|
|
a8dab94087 | ||
|
|
5a348da0e9 | ||
|
|
115b835b83 | ||
|
|
9df42799ff | ||
|
|
e1d3c01199 | ||
|
|
bdcc0f252b | ||
|
|
437aa1e9af | ||
|
|
6883bc7afc | ||
|
|
a2eef895bd | ||
|
|
64671c8ce7 | ||
|
|
252a27174e | ||
|
|
7c362af3de | ||
|
|
c6b851a2e6 | ||
|
|
ec4346aba3 | ||
|
|
791186a264 | ||
|
|
ab947f06aa | ||
|
|
cfa0ceb604 | ||
|
|
c7686ad57e | ||
|
|
8732b7cb4d | ||
|
|
fe9dcbb316 | ||
|
|
38d1a381e6 | ||
|
|
0b2f1d5675 | ||
|
|
caaa235c5d | ||
|
|
9a0126cde1 | ||
|
|
39d0c0fd8f | ||
|
|
be0b9979bc | ||
|
|
b3210f6c2c | ||
|
|
2357240d84 | ||
|
|
c2f0048931 | ||
|
|
d1ba314065 | ||
|
|
8a79ede285 | ||
|
|
c8ecd6ac8e | ||
|
|
13226adb2a | ||
|
|
e706aae41d | ||
|
|
91ad0df11c | ||
|
|
976627d974 | ||
|
|
6830f9861a | ||
|
|
2db307fc8d | ||
|
|
7fae43e1a5 | ||
|
|
8b60226497 | ||
|
|
ab8083dec4 | ||
|
|
a561713a48 | ||
|
|
00f3996cee | ||
|
|
9e4e79c5d7 | ||
|
|
61e1b8d859 | ||
|
|
165e8e8cba | ||
|
|
635fbcf0d5 | ||
|
|
815222ad80 | ||
|
|
64a9f15b1c | ||
|
|
abcdf39b20 | ||
|
|
16ee75313a | ||
|
|
bfd9938507 | ||
|
|
01f5f1b5ba | ||
|
|
b6706c7ac1 | ||
|
|
7723b30951 | ||
|
|
6d34151590 | ||
|
|
2230cbbe2a | ||
|
|
b49ba55658 | ||
|
|
0864154157 | ||
|
|
c4f64b1592 | ||
|
|
001d054924 | ||
|
|
5e590a4a5e | ||
|
|
22a2fe2cb4 | ||
|
|
f047ae6792 | ||
|
|
e1ef495071 | ||
|
|
209c6253a6 | ||
|
|
1acabb9d35 | ||
|
|
420495cb2d | ||
|
|
9309824874 | ||
|
|
4fc443e760 | ||
|
|
53399f06e5 | ||
|
|
4e3fda87a1 | ||
|
|
1ff3b3326c | ||
|
|
9f0ddda6ca | ||
|
|
8e3d30bd7f | ||
|
|
6ca3186bff | ||
|
|
68fadfe26c | ||
|
|
92bcdb5e53 | ||
|
|
04b1948ee9 | ||
|
|
6fdc16017a | ||
|
|
7f759d6bb5 | ||
|
|
1f227797c1 | ||
|
|
ab87c0a9ee | ||
|
|
6d960918e2 | ||
|
|
5797e32461 | ||
|
|
41da6c3b99 | ||
|
|
fe3a352511 | ||
|
|
b53f4214bc | ||
|
|
b6b1bcc5ad | ||
|
|
91117ca7c6 | ||
|
|
2d8e55a34e | ||
|
|
3a7292d3d0 | ||
|
|
3fea1c4e5f | ||
|
|
c2435470c1 | ||
|
|
1c993c10a1 | ||
|
|
0a62ce23af | ||
|
|
38efb8b3ad | ||
|
|
9ee7f5e0bd | ||
|
|
c798e1a2da | ||
|
|
7eb4713422 | ||
|
|
a9ed26fdbc | ||
|
|
a7451b6abe | ||
|
|
e61db642bc | ||
|
|
25a540c28b | ||
|
|
1993b8f8a6 | ||
|
|
38dd5612fd | ||
|
|
8a63c6f3a3 | ||
|
|
778d13dee7 | ||
|
|
2fd0d2baff | ||
|
|
399792803a | ||
|
|
8a6bbcb985 | ||
|
|
419349e13e | ||
|
|
6b0770fdd5 | ||
|
|
ee2b05da78 | ||
|
|
d900847bab | ||
|
|
8b56ebd566 | ||
|
|
a1f80f024e | ||
|
|
41de8a1309 | ||
|
|
33f08364e4 | ||
|
|
c5b95ed3c0 | ||
|
|
f7c8cabdfe | ||
|
|
0f1c424731 | ||
|
|
3fa00f603b | ||
|
|
f5004a66a1 | ||
|
|
b832b82ec6 | ||
|
|
fbd5b8b721 | ||
|
|
772dfe39dc | ||
|
|
c7e62142e9 | ||
|
|
6eb2b33124 | ||
|
|
b3ddf16d64 | ||
|
|
4a29aef19e | ||
|
|
7b8849493f | ||
|
|
2b588f1567 | ||
|
|
975f7c0332 |
76
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
Normal file
76
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]: "
|
||||
labels: ["bug", "triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
- type: dropdown
|
||||
id: category
|
||||
attributes:
|
||||
label: Category
|
||||
description: How would you catagorize this issue?
|
||||
multiple: true
|
||||
options:
|
||||
- Hardware Compatibility
|
||||
- BLE
|
||||
- Serial
|
||||
- WiFi
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: hardware
|
||||
attributes:
|
||||
label: Hardware
|
||||
description: What hardware are you encountering this issue on?
|
||||
multiple: true
|
||||
options:
|
||||
- Not Applicable
|
||||
- T-Beam
|
||||
- T-Beam 0.7
|
||||
- T-Lora v1
|
||||
- T-Lora v1.3
|
||||
- T-Lora v2 1.6
|
||||
- T-Echo
|
||||
- Rak4631
|
||||
- Rak11200
|
||||
- Heltec v1
|
||||
- Heltec v2
|
||||
- Heltec v2.1
|
||||
- Relay v1
|
||||
- Relay v2
|
||||
- DIY
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Firmware Version
|
||||
description: This can be found on the device's screen or via one of the apps.
|
||||
placeholder: x.x.x.yyyyyyy
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: body
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide details on what steps you performed for this to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: If you have any log output to help in diagnosing your bug, please provide it here.
|
||||
render: Shell
|
||||
validations:
|
||||
required: false
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
name: Bug report or feature proposal
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please - if you just have a question (i.e. not a bug report or a feature proposal), post in our [forum](https://meshtastic.discourse.group/) instead.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Device info:**
|
||||
- Device model: [e.g. TBEAM]
|
||||
- Software Version [e.g. 0.7.8]
|
||||
|
||||
**Smartphone information (if relevant):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- App Version [e.g. 0.7.2]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
39
.github/actions/initbuild/action.yml
vendored
39
.github/actions/initbuild/action.yml
vendored
@@ -1,39 +0,0 @@
|
||||
name: 'Common init'
|
||||
|
||||
# WARNING due to https://github.com/actions/runner/issues/646
|
||||
# this code can't work - must copy and paste into workflows for now because 'uses' is not supported
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
# We actually want to run this every time
|
||||
# if: steps.cache-pip.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
|
||||
# Don't cache for now because I want to be lazy with portuino updates githashes
|
||||
# - name: Cache platformio
|
||||
# uses: actions/cache@v1
|
||||
# id: cache-platformio # needed in if test
|
||||
# with:
|
||||
# path: ~/.platformio
|
||||
# key: ${{ runner.os }}-platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
|
||||
97
.github/workflows/main.yml
vendored
97
.github/workflows/main.yml
vendored
@@ -1,21 +1,11 @@
|
||||
name: Continuous Integration
|
||||
name: Continuous Integration (Legacy serial build)
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the master branch
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
# setup:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
workflow_dispatch:
|
||||
|
||||
# - name: Startup
|
||||
# run: echo "No action setup currently needed, skipping..."
|
||||
jobs:
|
||||
|
||||
ci-build:
|
||||
# needs: setup
|
||||
ci-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -23,6 +13,12 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Install cppcheck
|
||||
run: |
|
||||
sudo apt-get install -y cppcheck
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
@@ -36,9 +32,42 @@ jobs:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
#- name: Install linux apt packages
|
||||
# run: |
|
||||
# sudo apt-get install -y libgpiod-dev
|
||||
- name: Upgrade python tools and install platformio
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Check everything
|
||||
run: bin/check-all.sh
|
||||
|
||||
|
||||
|
||||
ci-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
# We actually want to run this every time
|
||||
@@ -81,22 +110,23 @@ jobs:
|
||||
echo "Simulator started, launching python test..."
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
|
||||
# - name: Build for tbeam
|
||||
# run: platformio run -e tbeam
|
||||
# - name: Build for heltec
|
||||
# run: platformio run -e heltec
|
||||
# - name: Build for wisblock RAK4631
|
||||
# run: platformio run -e rak4631
|
||||
- name: Cat bin/build-all.sh
|
||||
run: |
|
||||
cat bin/build-all.sh
|
||||
|
||||
- name: Build everything
|
||||
run: bin/build-all.sh
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: built
|
||||
path: release/archive/firmware-*.zip
|
||||
retention-days: 30
|
||||
name: firmware-${{ steps.version.outputs.version }}.zip
|
||||
path: release/archive/firmware-${{ steps.version.outputs.version }}.zip
|
||||
retention-days: 90
|
||||
|
||||
- name: Store debugging elf files as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
@@ -104,3 +134,18 @@ jobs:
|
||||
name: debug-elfs
|
||||
path: release/archive/elfs-*.zip
|
||||
retention-days: 7
|
||||
|
||||
- name: Download firmware.zip
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}.zip
|
||||
path: ./
|
||||
|
||||
- name: Pull request artifacts
|
||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||
uses: gavv/pull-request-artifacts@v1.0.0
|
||||
with:
|
||||
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
artifacts-branch: artifacts
|
||||
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
|
||||
|
||||
345
.github/workflows/main_matrix.yml
vendored
Normal file
345
.github/workflows/main_matrix.yml
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
name: Continuous Integration
|
||||
on:
|
||||
# # Triggers the workflow on push but only for the master branch
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.yml'
|
||||
- 'version.properties'
|
||||
|
||||
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
|
||||
pull_request_target:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.yml'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
check:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- board: rak11200
|
||||
- board: tlora-v2
|
||||
- board: tlora-v1
|
||||
- board: tlora_v1_3
|
||||
- board: tlora-v2-1-1.6
|
||||
- board: tbeam
|
||||
- board: heltec-v1
|
||||
- board: heltec-v2.0
|
||||
- board: heltec-v2.1
|
||||
- board: tbeam0.7
|
||||
- board: meshtastic-diy-v1
|
||||
- board: rak4631_5005
|
||||
- board: rak4631_19003
|
||||
- board: rak4631_5005_eink
|
||||
- board: t-echo
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Install cppcheck
|
||||
run: |
|
||||
sudo apt-get install -y cppcheck
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools and install platformio
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Check ${{ matrix.board }}
|
||||
run: bin/check-all.sh ${{ matrix.board }}
|
||||
|
||||
build-esp32:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- board: rak11200
|
||||
- board: tlora-v2
|
||||
- board: tlora-v1
|
||||
- board: tlora_v1_3
|
||||
- board: tlora-v2-1-1.6
|
||||
- board: tbeam
|
||||
- board: heltec-v1
|
||||
- board: heltec-v2.0
|
||||
- board: heltec-v2.1
|
||||
- board: tbeam0.7
|
||||
- board: meshtastic-diy-v1
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/meshtastic-web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
run: |
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ matrix.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.bin
|
||||
release/*.elf
|
||||
retention-days: 90
|
||||
|
||||
build-nrf52:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 2
|
||||
matrix:
|
||||
include:
|
||||
- board: rak4631_5005
|
||||
- board: rak4631_19003
|
||||
- board: rak4631_5005_eink
|
||||
- board: t-echo
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Build NRF52
|
||||
run: bin/build-nrf52.sh ${{ matrix.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
retention-days: 90
|
||||
|
||||
build-native:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
# We now run integration test before other build steps (to quickly see runtime failures)
|
||||
- name: Build for native
|
||||
run: platformio run -e native
|
||||
- name: Integration test
|
||||
run: |
|
||||
.pio/build/native/program &
|
||||
sleep 20 # 5 seconds was not enough
|
||||
echo "Simulator started, launching python test..."
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
|
||||
- name: Build Native
|
||||
run: bin/build-native.sh
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware-native-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/meshtasticd_linux_amd64
|
||||
release/device-*.sh
|
||||
release/device-*.bat
|
||||
retention-days: 90
|
||||
|
||||
after-checks:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
gather-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-esp32, build-nrf52, build-native]
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: ./
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
|
||||
- name: Move files up
|
||||
run: mv -b -t ./ ./*tbeam-*/littlefs*.bin ./*tbeam-*/system-info.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
./*.bin
|
||||
./*.uf2
|
||||
./meshtasticd_linux_amd64
|
||||
./device-*.sh
|
||||
./device-*.bat
|
||||
retention-days: 90
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}
|
||||
path: ./output
|
||||
|
||||
# For diagnostics
|
||||
- name: Show artifacts
|
||||
run: ls -lR
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: debug-elfs-${{ steps.version.outputs.version }}.zip
|
||||
path: ./*.elf
|
||||
retention-days: 90
|
||||
|
||||
- name: Create request artifacts
|
||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||
uses: gavv/pull-request-artifacts@v1.0.0
|
||||
with:
|
||||
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
artifacts-branch: artifacts
|
||||
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Make Release
|
||||
on:
|
||||
# Can optionally take parameters from the github UI, more info here https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/#:~:text=You%20can%20now%20create%20workflows,the%20workflow%20is%20run%20on.
|
||||
# workflow_dispatch:
|
||||
workflow_dispatch:
|
||||
# inputs:
|
||||
|
||||
# Only want to run if version.properties is bumped in master
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
# if: steps.cache-pip.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
|
||||
29
.github/workflows/update_protobufs.yml
vendored
29
.github/workflows/update_protobufs.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: "Update protobufs"
|
||||
name: "Update protobufs and regenerate classes"
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
@@ -11,14 +11,23 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Update Submodule
|
||||
- name: Update submodule
|
||||
run: |
|
||||
git pull --recurse-submodules
|
||||
git submodule update --remote --recursive
|
||||
- name: Commit update
|
||||
git submodule update --remote proto
|
||||
|
||||
- name: Download nanopb
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'bot@noreply.github.com'
|
||||
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
|
||||
git add proto
|
||||
git commit -m "Update protobuf submodule" && git push || echo "No changes to commit"
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.4-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.4-linux-x86.tar.gz
|
||||
mv nanopb-0.4.4-linux-x86 nanopb-0.4.4
|
||||
|
||||
- name: Re-generate protocol buffers
|
||||
run: |
|
||||
./bin/regen-protos.sh
|
||||
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
add-paths: |
|
||||
proto
|
||||
src/mesh
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,3 +26,6 @@ __pycache__
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
venv/
|
||||
release/
|
||||
|
||||
19
.vscode/extensions.json
vendored
19
.vscode/extensions.json
vendored
@@ -1,8 +1,11 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide",
|
||||
"xaver.clang-format"
|
||||
]
|
||||
}
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide",
|
||||
"xaver.clang-format"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
|
||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM ubuntu
|
||||
MAINTAINER Kevin Hester <kevinh@geeksville.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install wget python3 g++ zip python3-venv git vim
|
||||
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -O get-platformio.py; chmod +x get-platformio.py
|
||||
RUN python3 get-platformio.py
|
||||
RUN git clone https://github.com/meshtastic/Meshtastic-device.git
|
||||
RUN cd Meshtastic-device; git submodule update --init --recursive
|
||||
# only build the simulator
|
||||
RUN sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' Meshtastic-device/bin/build-all.sh
|
||||
RUN sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' Meshtastic-device/bin/build-all.sh
|
||||
RUN sed -i 's/echo "Building Filesystem.*/exit/' Meshtastic-device/bin/build-all.sh
|
||||
RUN . ~/.platformio/penv/bin/activate; cd Meshtastic-device; ./bin/build-all.sh
|
||||
|
||||
CMD ["/Meshtastic-device/release/latest/bins/universal/meshtasticd_linux_amd64"]
|
||||
72
README-docker.md
Normal file
72
README-docker.md
Normal file
@@ -0,0 +1,72 @@
|
||||
## What is Docker used for
|
||||
|
||||
Developers can simulate Device hardware by compiling and running
|
||||
a linux native binary application. If you do not own a Linux
|
||||
machine, or you just want to separate things, you might want
|
||||
to run simulator inside a docker container
|
||||
|
||||
## The Image
|
||||
To build docker image, type
|
||||
|
||||
`docker build -t meshtastic/device .`
|
||||
|
||||
## Usage
|
||||
|
||||
To run a container, type
|
||||
|
||||
`docker run --rm -p 4403:4403 meshtastic/device`
|
||||
|
||||
or, to get an interactive shell on the docker created container:
|
||||
|
||||
`docker run -it -p 4403:4403 meshtastic/device bash`
|
||||
|
||||
You might want to mount your local development folder:
|
||||
|
||||
`docker run -it --mount type=bind,source=/PathToMyProjects/Meshtastic/Meshtastic-device-mybranch,target=/Meshtastic-device-mybranch -p 4403:4403 meshtastic/device bash`
|
||||
|
||||
## Build the native application
|
||||
|
||||
Linux native application should be built inside the container.
|
||||
For this you must run container with interactive console
|
||||
"-it", as seen above.
|
||||
|
||||
First, some environment variables need to be set up with command:
|
||||
|
||||
`. ~/.platformio/penv/bin/activate`
|
||||
|
||||
You also want to make some adjustments in the bin/build-all.sh to conform the amd64 build:
|
||||
|
||||
```
|
||||
sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' bin/build-all.sh
|
||||
sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' bin/build-all.sh
|
||||
sed -i 's/echo "Building SPIFFS.*/exit/' bin/build-all.sh
|
||||
```
|
||||
|
||||
You can build amd64 image with command
|
||||
|
||||
`bin/build-all.sh`
|
||||
|
||||
## Executing the application interactively
|
||||
|
||||
The built binary file should be found under name
|
||||
`release/latest/bins/universal/meshtastic_linux_amd64`.
|
||||
If this is not the case, you can also use direct program name:
|
||||
`.pio/build/native/program`
|
||||
|
||||
To use python cli against exposed port 4403,
|
||||
type this in the host machine:
|
||||
|
||||
`meshtastic --info --host localhost`
|
||||
|
||||
## Stop the container
|
||||
|
||||
Run this to get the ID:
|
||||
|
||||
`docker ps`
|
||||
|
||||
Stop the container with command:
|
||||
|
||||
`docker kill <id>`
|
||||
|
||||
> Tip: you can just use the first few characters of the ID in docker commands
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
# Meshtastic-device
|
||||
[](https://open.vscode.dev/meshtastic/Meshtastic-device)
|
||||
[](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml)
|
||||

|
||||
|
||||
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
|
||||
|
||||
Update Instructions
|
||||
|
||||
[Using Meshtastic Flasher](https://meshtastic.org/docs/getting-started/meshtastic-flasher)
|
||||
|
||||
Manual Method
|
||||
|
||||
[For ESP32 devices click here](https://meshtastic.org/docs/getting-started/flashing-esp32)
|
||||
|
||||
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52)
|
||||
|
||||
For developer information and specific building instructions, please see the [developer doccumentation](https://meshtastic.org/docs/developers)
|
||||
For developer information and specific building instructions, please see the [developer documentation](https://meshtastic.org/docs/developers)
|
||||
|
||||
@@ -5,11 +5,11 @@ set -e
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
BOARDS_ESP32="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"
|
||||
BOARDS_ESP32="rak11200 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"
|
||||
#BOARDS_ESP32=tbeam
|
||||
|
||||
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
|
||||
BOARDS_NRF52="rak4631_5005 rak4631_19003 t-echo"
|
||||
BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo"
|
||||
#BOARDS_NRF52=""
|
||||
|
||||
OUTDIR=release/latest
|
||||
@@ -28,7 +28,7 @@ function do_build() {
|
||||
BOARD=$1
|
||||
isNrf=$3
|
||||
|
||||
echo "Building for $BOARD with $PLATFORMIO_BUILD_FLAGS"
|
||||
echo "Building for $BOARD ($isNrf) with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$BOARD/firmware.*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
@@ -59,6 +59,7 @@ function do_boards() {
|
||||
declare isNrf=$2
|
||||
for board in $boards; do
|
||||
# Build universal
|
||||
echo "about to build $board $isNrf"
|
||||
do_build $board "" "$isNrf"
|
||||
done
|
||||
}
|
||||
@@ -75,12 +76,12 @@ do_boards "$BOARDS_NRF52" "true"
|
||||
pio run --environment native
|
||||
cp .pio/build/native/program $OUTDIR/bins/universal/meshtasticd_linux_amd64
|
||||
|
||||
echo "Building SPIFFS for ESP32 targets"
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
pio run --environment tbeam -t buildfs
|
||||
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin
|
||||
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/littlefs-$VERSION.bin
|
||||
|
||||
# keep the bins in archive also
|
||||
cp $OUTDIR/bins/universal/spiffs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
|
||||
cp $OUTDIR/bins/universal/littlefs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
|
||||
|
||||
echo Updating android bins $OUTDIR/forandroid
|
||||
rm -rf $OUTDIR/forandroid
|
||||
@@ -102,9 +103,9 @@ XML
|
||||
|
||||
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
|
||||
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
|
||||
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
|
||||
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/littlefs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
|
||||
echo Generating $ARCHIVEDIR/elfs-$VERSION.zip
|
||||
rm -f $ARCHIVEDIR/elfs-$VERSION.zip
|
||||
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*
|
||||
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*
|
||||
|
||||
echo BUILT ALL
|
||||
|
||||
43
bin/build-esp32.sh
Executable file
43
bin/build-esp32.sh
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
OUTDIR=release/
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio lib update
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
# Are we building a universal/regionless rom?
|
||||
export HW_VERSION="1.0"
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying ESP32 bin file"
|
||||
SRCBIN=.pio/build/$1/firmware.bin
|
||||
cp $SRCBIN $OUTDIR/$basename.bin
|
||||
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
pio run --environment tbeam -t buildfs
|
||||
cp .pio/build/tbeam/spiffs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||
cp images/system-info.bin $OUTDIR/system-info.bin
|
||||
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
26
bin/build-native.sh
Executable file
26
bin/build-native.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
OUTDIR=release/
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
|
||||
mkdir -p $OUTDIR/
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio lib update
|
||||
|
||||
pio run --environment native
|
||||
cp .pio/build/native/program $OUTDIR/meshtasticd_linux_amd64
|
||||
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
|
||||
37
bin/build-nrf52.sh
Executable file
37
bin/build-nrf52.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
OUTDIR=release/
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio lib update
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
export HW_VERSION="1.0"
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
|
||||
echo "Generating NRF52 uf2 file"
|
||||
SRCHEX=.pio/build/$1/firmware.hex
|
||||
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840
|
||||
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
26
bin/check-all.sh
Executable file
26
bin/check-all.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Note: This is a prototype for how we could add static code analysis to the CI.
|
||||
|
||||
set -e
|
||||
|
||||
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="$@"
|
||||
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_5005 rak4631_19003 rak11200 t-echo"
|
||||
fi
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
CHECK=""
|
||||
for BOARD in $BOARDS; do
|
||||
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
|
||||
@@ -30,7 +30,7 @@ IF EXIST %FILENAME% (
|
||||
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
||||
%PYTHON% -m esptool --baud 921600 erase_flash
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x1000 system-info.bin
|
||||
for %%f in (spiffs-*.bin) do (
|
||||
for %%f in (littlefs-*.bin) do (
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x00390000 %%f
|
||||
)
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME%
|
||||
|
||||
@@ -11,7 +11,7 @@ Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
|
||||
Flash image file to device, but first erasing and writing system information"
|
||||
|
||||
-h Display this help and exit
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
|
||||
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
|
||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
EOF
|
||||
@@ -46,10 +46,10 @@ shift "$((OPTIND-1))"
|
||||
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
$PYTHON -m esptool erase_flash
|
||||
$PYTHON -m esptool write_flash 0x1000 system-info.bin
|
||||
$PYTHON -m esptool write_flash 0x00390000 spiffs-*.bin
|
||||
$PYTHON -m esptool write_flash 0x10000 ${FILENAME}
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin
|
||||
"$PYTHON" -m esptool write_flash 0x00390000 littlefs-*.bin
|
||||
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
51
bin/mklittlefs.py
Executable file
51
bin/mklittlefs.py
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
import getopt
|
||||
import sys
|
||||
import os
|
||||
from littlefs import LittleFS
|
||||
from pathlib import Path
|
||||
|
||||
print( "Building LittleFS image..." )
|
||||
|
||||
argList = sys.argv[1:]
|
||||
arxx = { argList[i]: argList[i+1] for i in range(0, len(argList)-1, 2) }
|
||||
|
||||
dataPath = arxx["-c"]
|
||||
blockSize = int(arxx["-b"])
|
||||
blockCount = int(arxx["-s"]) / blockSize
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
os.chdir(dataPath)
|
||||
|
||||
fileList = []
|
||||
dirList = []
|
||||
|
||||
for (dirpath, dirnames, filenames) in os.walk('.'):
|
||||
for f in filenames:
|
||||
if (f[:1] != '.'):
|
||||
fileList.append( os.path.join(dirpath, f) )
|
||||
for d in dirnames:
|
||||
if (d[:1] != '.'):
|
||||
dirList.append( os.path.join(dirpath, d) )
|
||||
|
||||
fs = LittleFS(block_size=blockSize, block_count=blockCount) # create a 448kB partition
|
||||
|
||||
for curDir in dirList:
|
||||
print( "Creating dir " + curDir )
|
||||
fs.mkdir( curDir )
|
||||
|
||||
for curFile in fileList:
|
||||
print( "Adding file " + curFile )
|
||||
with open( curFile, 'rb' ) as f:
|
||||
data = f.read()
|
||||
|
||||
with fs.open( curFile, 'wb') as fh:
|
||||
fh.write( data )
|
||||
|
||||
outName = argList[-1]
|
||||
|
||||
os.chdir(cwd)
|
||||
|
||||
with open(outName, 'wb') as fh:
|
||||
fh.write(fs.context.buffer)
|
||||
@@ -6,6 +6,13 @@ import traceback
|
||||
import sys
|
||||
from readprops import readProps
|
||||
|
||||
Import("env")
|
||||
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/bin/mklittlefs.py' )
|
||||
try:
|
||||
import littlefs
|
||||
except ImportError:
|
||||
env.Execute("$PYTHONEXE -m pip install --user littlefs-python")
|
||||
|
||||
Import("projenv")
|
||||
|
||||
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
||||
|
||||
39
boards/wiscore_rak11200.json
Normal file
39
boards/wiscore_rak11200.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "esp32_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": "-DARDUINO_ESP32_DEV",
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "40000000L",
|
||||
"flash_mode": "dio",
|
||||
"mcu": "esp32",
|
||||
"variant": "WisCore_RAK11200_Board"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi",
|
||||
"bluetooth",
|
||||
"ethernet",
|
||||
"can"
|
||||
],
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "WisCore RAK11200 Board",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"protocols": [
|
||||
"esptool",
|
||||
"espota",
|
||||
"ftdi"
|
||||
],
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.rakwireless.com",
|
||||
"vendor": "RAKwireless"
|
||||
}
|
||||
@@ -63,7 +63,7 @@ You probably don't care about this section - skip to the next one.
|
||||
|
||||
## Multichannel support
|
||||
|
||||
* DONE cleanup the external notification and serial plugins
|
||||
* DONE cleanup the external notification and serial modules
|
||||
* non ack version of stress test fails sometimes!
|
||||
* tx fault test has a bug #734 - * turn off fault 8: https://github.com/meshtastic/Meshtastic-device/issues/734
|
||||
* DONE move device types into an enum in nodeinfo
|
||||
@@ -71,7 +71,7 @@ You probably don't care about this section - skip to the next one.
|
||||
* nrf52 should preserve local time across reset
|
||||
* cdcacm bug on nrf52: emittx thinks it emitted but client sees nothing. works again later
|
||||
* nrf52: segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger)
|
||||
* DONE call RouterPlugin for *all* packets - not just Router packets
|
||||
* DONE call RouterModule for *all* packets - not just Router packets
|
||||
* DONE generate channel hash from the name of the channel+the psk (not just one or the other)
|
||||
* DONE send a hint that can be used to select which channel to try and hash against with each message
|
||||
* DONE remove deprecated
|
||||
@@ -79,13 +79,13 @@ You probably don't care about this section - skip to the next one.
|
||||
* DONE set mynodeinfo.max_channels
|
||||
* DONE set mynodeinfo.num_bands (formerly num_channels)
|
||||
* DONE fix sniffing of non Routing packets
|
||||
* DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI)
|
||||
* DONE enable remote setttings access by moving settings operations into a regular module (move settings ops out of PhoneAPI)
|
||||
* DONE move portnum up?
|
||||
* DONE remove region specific builds from the firmware
|
||||
* DONE test single channel without python
|
||||
* DONE Use "default" for name if name is empty
|
||||
* DONE fix python data packet receiving (nothing showing in log?)
|
||||
* DONE implement 'get channels' Admin plugin operation
|
||||
* DONE implement 'get channels' Admin module operation
|
||||
* DONE use get-channels from python
|
||||
* DONE use get channels & get settings from android
|
||||
* DONE use set-channel from python
|
||||
@@ -98,7 +98,7 @@ You probably don't care about this section - skip to the next one.
|
||||
* DONE fix setch-fast in python tool
|
||||
* age out pendingrequests in the python API
|
||||
* DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection
|
||||
* DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
|
||||
* DONE combine acks and responses in a single message if possible (do routing module LAST and drop ACK if someone else has already replied)
|
||||
* DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
|
||||
* DONE fix 1.1.50 android debug panel display
|
||||
* DONE test android channel setting
|
||||
@@ -118,7 +118,7 @@ You probably don't care about this section - skip to the next one.
|
||||
* use single byte 'well known' channel names for admin, gpio, etc...
|
||||
* use presence of gpio channel to enable gpio ops, same for serial etc...
|
||||
* DONE restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
|
||||
* DONE add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
|
||||
* DONE add channel restrictions for modules (and restrict routing module to the "control" channel)
|
||||
* stress test multi channel
|
||||
* DONE investigate @mc-hamster report of heap corruption
|
||||
* DONE use set-user from android
|
||||
@@ -134,7 +134,7 @@ You probably don't care about this section - skip to the next one.
|
||||
* allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead
|
||||
* DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key.
|
||||
* when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets
|
||||
* DONE confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
|
||||
* DONE confirm we are still calling the modules for messages inbound from the phone (or generated locally)
|
||||
* DONE confirm we are still multi hop routing flood broadcasts
|
||||
* DONE confirm we are still doing resends on unicast reliable packets
|
||||
* add history to routed packets: https://meshtastic.discourse.group/t/packet-source-tracking/2764/2
|
||||
@@ -142,7 +142,7 @@ You probably don't care about this section - skip to the next one.
|
||||
* DONE move acks into routing
|
||||
* DONE make all subpackets different versions of data
|
||||
* DONE move routing control into a data packet
|
||||
* have phoneapi done via plugin (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
|
||||
* have phoneapi done via module (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
|
||||
* use reference counting and dynamic sizing for meshpackets. - use https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 (already used in arduino)
|
||||
* let multiple PhoneAPI endpoints work at once
|
||||
* allow multiple simultaneous bluetooth connections (create the bluetooth phoneapi instance dynamically based on client id)
|
||||
@@ -182,13 +182,13 @@ For app cleanup:
|
||||
* DONE require a recent python api to talk to these new device loads
|
||||
* DONE require a recent android app to talk to these new device loads
|
||||
* DONE fix handleIncomingPosition
|
||||
* DONE move want_replies handling into plugins
|
||||
* DONE move want_replies handling into modules
|
||||
* DONE on android for received positions handle either old or new positions / user messages
|
||||
* DONE on android side send old or new positions as needed / user messages
|
||||
* DONE test python side handle new position/user messages
|
||||
* DONE make a gpio example. --gpiowrb 4 1, --gpiord 0x444, --gpiowatch 0x3ff
|
||||
* DONE fix position sending to use new plugin
|
||||
* DONE Add SinglePortNumPlugin - as the new most useful baseclass
|
||||
* DONE fix position sending to use new module
|
||||
* DONE Add SinglePortNumModule - as the new most useful baseclass
|
||||
* DONE move positions into regular data packets (use new app framework)
|
||||
* DONE move user info into regular data packets (use new app framework)
|
||||
* DONE test that positions, text messages and user info still work
|
||||
|
||||
302
platformio.ini
302
platformio.ini
@@ -11,19 +11,27 @@
|
||||
[platformio]
|
||||
default_envs = tbeam
|
||||
;default_envs = tbeam0.7
|
||||
;default_envs = heltec-v2.0
|
||||
;default_envs = heltec-v1
|
||||
;default_envs = heltec-v2.0
|
||||
;default_envs = heltec-v2.1
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora_v1_3
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = tlora-v2-1-1.6
|
||||
;default_envs = lora-relay-v1 # nrf board
|
||||
;default_envs = t-echo
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = rak4631
|
||||
;default_envs = rak4630
|
||||
;default_envs = rak4631_5005
|
||||
;default_envs = rak4631_5005_eink
|
||||
;default_envs = rak4631_19003
|
||||
;default_envs = meshtastic-diy-v1
|
||||
;default_envs = meshtastic-diy-v1.1
|
||||
|
||||
; board specific config can be moved to the respective 'variants' file.
|
||||
; See https://docs.platformio.org/en/latest/projectconf/section_platformio.html#extra-configs
|
||||
extra_configs = variants/*/platformio.ini
|
||||
|
||||
[common]
|
||||
; common is not currently used
|
||||
@@ -70,7 +78,7 @@ debug_tool = jlink
|
||||
; monitor adapter_khz 10000
|
||||
|
||||
lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#d90231dedbb2f52bd7a32fb8ed8edec52cf4a8cb ; ESP8266_SSD1306
|
||||
https://github.com/meshtastic/OneButton.git#3bcba9492d01e2a8a86f46700ab16f96dd2cf1f5 ; OneButton library for non-blocking button debounce
|
||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||
https://github.com/meshtastic/arduino-fsm.git
|
||||
@@ -82,8 +90,12 @@ lib_deps =
|
||||
SPI
|
||||
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
PubSubClient
|
||||
|
||||
; Common settings for conventional (non Portduino) Ardino targets
|
||||
|
||||
; Used for the code analysis in PIO Home / Inspect
|
||||
check_tool = cppcheck
|
||||
check_skip_packages = yes
|
||||
|
||||
; Common settings for conventional (non Portduino) Arduino targets
|
||||
[arduino_base]
|
||||
|
||||
framework = arduino
|
||||
@@ -96,6 +108,17 @@ build_flags = ${env.build_flags} -Os
|
||||
|
||||
src_filter = ${env.src_filter} -<portduino/>
|
||||
|
||||
; Common libs for environmental measurements (not included in native / portduino)
|
||||
[environmental]
|
||||
lib_deps =
|
||||
adafruit/DHT sensor library@^1.4.1
|
||||
adafruit/Adafruit Unified Sensor@^1.1.4
|
||||
paulstoffregen/OneWire@^2.3.5
|
||||
robtillaart/DS18B20@^0.1.11
|
||||
adafruit/Adafruit BME280 Library@^2.2.2
|
||||
adafruit/Adafruit BME680 Library@^2.0.1
|
||||
adafruit/Adafruit MCP9808 Library@^2.0.0
|
||||
|
||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||
[esp32_base]
|
||||
extends = arduino_base
|
||||
@@ -114,14 +137,12 @@ build_flags =
|
||||
-DAXP_DEBUG_PORT=Serial
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git
|
||||
adafruit/DHT sensor library@^1.4.1
|
||||
adafruit/Adafruit Unified Sensor@^1.1.4
|
||||
paulstoffregen/OneWire@^2.3.5
|
||||
robtillaart/DS18B20@^0.1.11
|
||||
h2zero/NimBLE-Arduino@1.3.4
|
||||
h2zero/NimBLE-Arduino@1.3.6
|
||||
tobozo/ESP32-targz@^1.1.4
|
||||
arduino-libraries/NTPClient#531eff39d9fbc831f3d03f706a161739203fbe2a
|
||||
lorol/LittleFS_esp32@^1.0.6
|
||||
|
||||
# Hmm - this doesn't work yet
|
||||
# board_build.ldscript = linker/esp32.extram.bss.ld
|
||||
@@ -150,78 +171,6 @@ board_build.partitions = partition-table.csv
|
||||
|
||||
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
|
||||
|
||||
; The 1.0 release of the TBEAM board
|
||||
[env:tbeam]
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TBEAM_V10
|
||||
|
||||
; The original TBEAM board without the AXP power chip and a few other changes
|
||||
; Note: I've heard reports this didn't work. Disabled until someone with a 0.7 can test and debug.
|
||||
[env:tbeam0.7]
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TBEAM_V07
|
||||
|
||||
[env:heltec-v1]
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
extends = esp32_base
|
||||
board = heltec_wifi_lora_32
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D HELTEC_V1
|
||||
|
||||
[env:heltec-v2.0]
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
extends = esp32_base
|
||||
board = heltec_wifi_lora_32_V2
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D HELTEC_V2_0
|
||||
|
||||
[env:heltec-v2.1]
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
extends = esp32_base
|
||||
board = heltec_wifi_lora_32_V2
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D HELTEC_V2_1
|
||||
|
||||
[env:tlora-v1]
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V1
|
||||
|
||||
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
|
||||
[env:tlora_v1_3]
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V1_3
|
||||
|
||||
[env:tlora-v2]
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V2
|
||||
|
||||
[env:tlora-v2-1-1.6]
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V2_1_16
|
||||
|
||||
; Meshtastic DIY v1 by Nano VHF Schematic based on ESP32-WROOM-32 (38 pins) devkit & EBYTE E22 SX1262/SX1268 module
|
||||
[env:meshtastic-diy-v1]
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-D DIY_V1
|
||||
-D EBYTE_E22
|
||||
|
||||
; The Heltec Cubecell plus
|
||||
; IMPORTANT NOTE: This target doesn't yet work and probably won't ever work. I'm keeping it around for now.
|
||||
; For more details see my post in the forum.
|
||||
@@ -247,7 +196,7 @@ build_flags =
|
||||
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
|
||||
;-DCFG_DEBUG=3
|
||||
src_filter =
|
||||
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32> -<mqtt/>
|
||||
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
; monitor_port = /dev/ttyACM1
|
||||
@@ -291,42 +240,17 @@ extends = nrf52_base
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental.lib_deps}
|
||||
Adafruit nRFCrypto
|
||||
# Adafruit TinyUSB Arduino
|
||||
# add Adafruit nRFCrypto platform IO automated scan is broken
|
||||
|
||||
[env:lora_isp4520]
|
||||
extends = nrf52_base
|
||||
board = lora_isp4520
|
||||
|
||||
# add our variants files to the include and src paths
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_isp4520
|
||||
|
||||
# No screen and GPS on the board. We still need RTC.cpp for the RTC clock.
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/lora_isp4520> -<graphics> -<gps> +<gps/GPS.cpp> +<gps/RTC.cpp>
|
||||
lib_ignore = ${nrf52_base.lib_ignore}
|
||||
ESP8266_SSD1306
|
||||
SparkFun Ublox Arduino Library
|
||||
AXP202X_Library
|
||||
TinyGPSPlus
|
||||
|
||||
upload_protocol = jlink
|
||||
monitor_port = /dev/ttyUSB0
|
||||
|
||||
; The NRF52840-dk development board
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:nrf52840dk]
|
||||
extends = nrf52840_base
|
||||
board = nrf52840_dk
|
||||
|
||||
; The NRF52840-dk development board, but @geeksville's board - which has a busted oscilliator
|
||||
[env:nrf52840dk-geeksville]
|
||||
extends = nrf52840_base
|
||||
board = nrf52840_dk_modified
|
||||
# add our variants files to the include and src paths
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/pca10056-rc-clock
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/pca10056-rc-clock>
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:feather_nrf52832]
|
||||
extends = nrf52_base
|
||||
@@ -343,161 +267,3 @@ monitor_speed = 115200
|
||||
|
||||
# For experimenting with RAM sizes
|
||||
# board_build.ldscript = linker/nrf52840_s140_sim832.ld
|
||||
|
||||
; The very slick RAK wireless RAK 4631 / 4630 board
|
||||
[env:rak4631_5005]
|
||||
extends = nrf52840_base
|
||||
board = wiscore_rak4631
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_5005
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
|
||||
debug_tool = jlink
|
||||
|
||||
[env:rak4631_19003]
|
||||
extends = nrf52840_base
|
||||
board = wiscore_rak4631
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_19003
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
;upload_protocol = jlink
|
||||
|
||||
; Note, this board is not yet supported! It will not work without futher development.
|
||||
; THIS IS UNTESTED (I don't have this board), but other developers can use it as a starting point
|
||||
[env:rak4600]
|
||||
extends = nrf52_base
|
||||
board = wiscore_rak4600
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/WisCore_RAK4600_Board
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4600_Board>
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
|
||||
; The PPR board
|
||||
[env:ppr]
|
||||
extends = nrf52_base
|
||||
board = ppr
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
UC1701
|
||||
|
||||
; The PPR board
|
||||
[env:ppr1]
|
||||
extends = nrf52_base
|
||||
board = ppr1
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/ppr1
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/ppr1>
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
|
||||
; First prototype eink/nrf52840/sx1262 device
|
||||
[env:t-echo]
|
||||
extends = nrf52840_base
|
||||
board = t-echo
|
||||
debug_tool = jlink
|
||||
upload_protocol = jlink
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library - NOTE: WE NOT LONGER USE TFT_eSPI, it was for an earlier version of the TTGO eink screens
|
||||
# -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/t-echo>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
https://github.com/geeksville/GxEPD2.git
|
||||
adafruit/Adafruit BusIO
|
||||
;upload_protocol = fs
|
||||
|
||||
; First prototype eink/nrf52840/sx1262 device (removed from build because didn't ship in quantity)
|
||||
;[env:eink0.1]
|
||||
;extends = nrf52840_base
|
||||
;board = eink0.1
|
||||
;# add our variants files to the include and src paths
|
||||
;# define build flags for the TFT_eSPI library
|
||||
;build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
|
||||
; -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
;src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
|
||||
;lib_deps =
|
||||
; ${nrf52840_base.lib_deps}
|
||||
; https://github.com/geeksville/EPD_Libraries.git
|
||||
; TFT_eSPI
|
||||
|
||||
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
|
||||
[env:lora-relay-v1]
|
||||
extends = nrf52840_base
|
||||
board = lora-relay-v1
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1
|
||||
-DUSER_SETUP_LOADED
|
||||
-DTFT_WIDTH=80
|
||||
-DTFT_HEIGHT=160
|
||||
-DST7735_GREENTAB160x80
|
||||
-DST7735_DRIVER
|
||||
-DTFT_CS=ST7735_CS
|
||||
-DTFT_DC=ST7735_RS
|
||||
-DTFT_RST=ST7735_RESET
|
||||
-DSPI_FREQUENCY=27000000
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v1>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
|
||||
TFT_eSPI
|
||||
|
||||
; The https://github.com/BigCorvus/LoRa-BLE-Relay-v2 board by @BigCorvus
|
||||
[env:lora-relay-v2]
|
||||
extends = nrf52840_base
|
||||
board = lora-relay-v2
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2
|
||||
-DUSER_SETUP_LOADED
|
||||
-DTFT_WIDTH=80
|
||||
-DTFT_HEIGHT=160
|
||||
-DST7735_GREENTAB160x80
|
||||
-DST7735_DRIVER
|
||||
-DTFT_CS=ST7735_CS
|
||||
-DTFT_DC=ST7735_RS
|
||||
-DTFT_RST=ST7735_RESET
|
||||
-DSPI_FREQUENCY=27000000
|
||||
-DTFT_WR=ST7735_SDA
|
||||
-DTFT_SCLK=ST7735_SCK
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v2>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
|
||||
TFT_eSPI
|
||||
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[env:native]
|
||||
platform = https://github.com/geeksville/platform-native.git
|
||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
||||
build_flags = ${arduino_base.build_flags} -O0
|
||||
framework = arduino
|
||||
board = cross_platform
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
rweather/Crypto
|
||||
|
||||
; The Portduino based sim environment on top of a linux OS and touching linux hardware devices
|
||||
[env:linux]
|
||||
platform = https://github.com/geeksville/platform-native.git
|
||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
||||
build_flags = ${arduino_base.build_flags} -O0 -lgpiod
|
||||
framework = arduino
|
||||
board = linux_hardware
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
rweather/Crypto
|
||||
|
||||
; The GenieBlocks LORA prototype board
|
||||
; note: @geeksville disabled because genieblocks_lora is not checked into the boards directory, please send in a PR to add it ;-)
|
||||
;[env:genieblocks_lora]
|
||||
;extends = esp32_base
|
||||
;board = genieblocks_lora
|
||||
;build_flags =
|
||||
; ${esp32_base.build_flags} -D GENIEBLOCKS
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 18fc4cdb52...f6ba3722be
220
src/ButtonThread.h
Normal file
220
src/ButtonThread.h
Normal file
@@ -0,0 +1,220 @@
|
||||
#include "configuration.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "power.h"
|
||||
#include "buzz.h"
|
||||
#include <OneButton.h>
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#endif
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
/**
|
||||
* Watch a GPIO and if we get an IRQ, wake the main thread.
|
||||
* Use to add wake on button press
|
||||
*/
|
||||
void wakeOnIrq(int irq, int mode)
|
||||
{
|
||||
attachInterrupt(
|
||||
irq,
|
||||
[] {
|
||||
BaseType_t higherWake = 0;
|
||||
mainDelay.interruptFromISR(&higherWake);
|
||||
},
|
||||
FALLING);
|
||||
}
|
||||
|
||||
class ButtonThread : public concurrency::OSThread
|
||||
{
|
||||
// Prepare for button presses
|
||||
#ifdef BUTTON_PIN
|
||||
OneButton userButton;
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
OneButton userButtonAlt;
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
OneButton userButtonTouch;
|
||||
#endif
|
||||
static bool shutdown_on_long_stop;
|
||||
|
||||
public:
|
||||
static uint32_t longPressTime;
|
||||
|
||||
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
|
||||
ButtonThread() : OSThread("Button")
|
||||
{
|
||||
#ifdef BUTTON_PIN
|
||||
userButton = OneButton(BUTTON_PIN, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButton.attachClick(userButtonPressed);
|
||||
userButton.attachDuringLongPress(userButtonPressedLong);
|
||||
userButton.attachDoubleClick(userButtonDoublePressed);
|
||||
userButton.attachMultiClick(userButtonMultiPressed);
|
||||
userButton.attachLongPressStart(userButtonPressedLongStart);
|
||||
userButton.attachLongPressStop(userButtonPressedLongStop);
|
||||
wakeOnIrq(BUTTON_PIN, FALLING);
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButtonAlt.attachClick(userButtonPressed);
|
||||
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
|
||||
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
|
||||
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
|
||||
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
|
||||
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
|
||||
#endif
|
||||
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN_TOUCH, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButtonTouch.attachClick(touchPressed);
|
||||
userButtonTouch.attachDuringLongPress(touchPressedLong);
|
||||
userButtonTouch.attachDoubleClick(touchDoublePressed);
|
||||
userButtonTouch.attachLongPressStart(touchPressedLongStart);
|
||||
userButtonTouch.attachLongPressStop(touchPressedLongStop);
|
||||
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
/// If the button is pressed we suppress CPU sleep until release
|
||||
int32_t runOnce() override
|
||||
{
|
||||
canSleep = true; // Assume we should not keep the board awake
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
userButton.tick();
|
||||
canSleep &= userButton.isIdle();
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
userButtonAlt.tick();
|
||||
canSleep &= userButtonAlt.isIdle();
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
userButtonTouch.tick();
|
||||
canSleep &= userButtonTouch.isIdle();
|
||||
#endif
|
||||
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
|
||||
// else DEBUG_MSG("sleep ok\n");
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
private:
|
||||
static void touchPressed()
|
||||
{
|
||||
screen->forceDisplay();
|
||||
DEBUG_MSG("touch press!\n");
|
||||
}
|
||||
static void touchDoublePressed()
|
||||
{
|
||||
DEBUG_MSG("touch double press!\n");
|
||||
}
|
||||
static void touchPressedLong()
|
||||
{
|
||||
DEBUG_MSG("touch press long!\n");
|
||||
}
|
||||
static void touchDoublePressedLong()
|
||||
{
|
||||
DEBUG_MSG("touch double pressed!\n");
|
||||
}
|
||||
static void touchPressedLongStart()
|
||||
{
|
||||
DEBUG_MSG("touch long press start!\n");
|
||||
}
|
||||
static void touchPressedLongStop()
|
||||
{
|
||||
DEBUG_MSG("touch long press stop!\n");
|
||||
}
|
||||
|
||||
|
||||
static void userButtonPressed()
|
||||
{
|
||||
// DEBUG_MSG("press!\n");
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
}
|
||||
static void userButtonPressedLong()
|
||||
{
|
||||
// DEBUG_MSG("Long press!\n");
|
||||
#ifndef NRF52_SERIES
|
||||
screen->adjustBrightness();
|
||||
#endif
|
||||
// If user button is held down for 5 seconds, shutdown the device.
|
||||
if (millis() - longPressTime > 5 * 1000) {
|
||||
#ifdef TBEAM_V10
|
||||
if (axp192_found == true) {
|
||||
setLed(false);
|
||||
power->shutdown();
|
||||
}
|
||||
#elif NRF52_SERIES
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
if (!shutdown_on_long_stop) {
|
||||
screen->startShutdownScreen();
|
||||
DEBUG_MSG("Shutdown from long press");
|
||||
playBeep();
|
||||
ledOff(PIN_LED1);
|
||||
ledOff(PIN_LED2);
|
||||
shutdown_on_long_stop = true;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
|
||||
}
|
||||
}
|
||||
|
||||
static void userButtonDoublePressed()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
disablePin();
|
||||
#elif defined(HAS_EINK)
|
||||
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void userButtonMultiPressed()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
clearNVS();
|
||||
#endif
|
||||
#ifdef NRF52_SERIES
|
||||
clearBonds();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void userButtonPressedLongStart()
|
||||
{
|
||||
DEBUG_MSG("Long press start!\n");
|
||||
longPressTime = millis();
|
||||
}
|
||||
|
||||
static void userButtonPressedLongStop()
|
||||
{
|
||||
DEBUG_MSG("Long press stop!\n");
|
||||
longPressTime = 0;
|
||||
if (shutdown_on_long_stop) {
|
||||
playShutdownMelody();
|
||||
delay(3000);
|
||||
power->shutdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
61
src/DebugConfiguration.h
Normal file
61
src/DebugConfiguration.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// DEBUG LED
|
||||
#ifndef LED_INVERTED
|
||||
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// DEBUG
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#ifdef CONSOLE_MAX_BAUD
|
||||
#define SERIAL_BAUD CONSOLE_MAX_BAUD
|
||||
#else
|
||||
#define SERIAL_BAUD 921600 // Serial debug baud rate
|
||||
#endif
|
||||
|
||||
#include "SerialConsole.h"
|
||||
|
||||
#define DEBUG_PORT (*console) // Serial debug port
|
||||
|
||||
// What platforms should use SEGGER?
|
||||
#ifdef NRF52_SERIES
|
||||
|
||||
// Always include the SEGGER code on NRF52 - because useful for debugging
|
||||
#include "SEGGER_RTT.h"
|
||||
|
||||
// The channel we send stdout data to
|
||||
#define SEGGER_STDOUT_CH 0
|
||||
|
||||
// Debug printing to segger console
|
||||
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
|
||||
|
||||
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
|
||||
// use SEGGER for debug output
|
||||
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
|
||||
// No serial ports on this board - ONLY use segger in memory console
|
||||
#define USE_SEGGER
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
|
||||
#endif
|
||||
|
||||
#ifdef USE_SEGGER
|
||||
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
#ifdef DEBUG_PORT
|
||||
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_MSG(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// AXP192 (Rev1-specific options)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define GPS_POWER_CTRL_CH 3
|
||||
#define LORA_POWER_CTRL_CH 2
|
||||
|
||||
// Default Bluetooth PIN
|
||||
#define defaultBLEPin 123456
|
||||
@@ -3,20 +3,20 @@
|
||||
|
||||
void fsInit()
|
||||
{
|
||||
#ifdef FS
|
||||
if (!FSBegin())
|
||||
#ifdef FSCom
|
||||
if (!FSBegin())
|
||||
{
|
||||
DEBUG_MSG("ERROR filesystem mount Failed\n");
|
||||
assert(0); // FIXME - report failure to phone
|
||||
}
|
||||
|
||||
DEBUG_MSG("Filesystem files:\n");
|
||||
File dir = FS.open("/");
|
||||
File dir = FSCom.open("/");
|
||||
File f = dir.openNextFile();
|
||||
while (f) {
|
||||
DEBUG_MSG(" %s\n", f.name());
|
||||
f.close();
|
||||
f = dir.openNextFile();
|
||||
f = dir.openNextFile();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -7,22 +7,22 @@
|
||||
#ifdef PORTDUINO
|
||||
// Portduino version
|
||||
#include "PortduinoFS.h"
|
||||
#define FS PortduinoFS
|
||||
#define FSCom PortduinoFS
|
||||
#define FSBegin() true
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
#elif !defined(NO_ESP32)
|
||||
// ESP32 version
|
||||
#include "SPIFFS.h"
|
||||
#define FS SPIFFS
|
||||
#define FSBegin() FS.begin(true)
|
||||
#include "LITTLEFS.h"
|
||||
#define FSCom LITTLEFS
|
||||
#define FSBegin() FSCom.begin(true)
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
#else
|
||||
// NRF52 version
|
||||
#include "InternalFileSystem.h"
|
||||
#define FS InternalFS
|
||||
#define FSBegin() FS.begin()
|
||||
#define FSCom InternalFS
|
||||
#define FSBegin() FSCom.begin()
|
||||
using namespace Adafruit_LittleFS_Namespace;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class GPSStatus : public Status
|
||||
}
|
||||
|
||||
// preferred method
|
||||
GPSStatus(bool hasLock, bool isConnected, Position pos)
|
||||
GPSStatus(bool hasLock, bool isConnected, const Position& pos)
|
||||
: Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
@@ -63,7 +63,9 @@ class GPSStatus : public Status
|
||||
|
||||
int32_t getLatitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
#if GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed latitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.latitude_i;
|
||||
} else {
|
||||
@@ -73,7 +75,9 @@ class GPSStatus : public Status
|
||||
|
||||
int32_t getLongitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
#if GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed longitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.longitude_i;
|
||||
} else {
|
||||
@@ -83,7 +87,9 @@ class GPSStatus : public Status
|
||||
|
||||
int32_t getAltitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
#if GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed altitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.altitude;
|
||||
} else {
|
||||
@@ -149,4 +155,4 @@ class GPSStatus : public Status
|
||||
|
||||
} // namespace meshtastic
|
||||
|
||||
extern meshtastic::GPSStatus *gpsStatus;
|
||||
extern meshtastic::GPSStatus *gpsStatus;
|
||||
|
||||
@@ -47,7 +47,7 @@ template <class Callback, class T> class CallbackObserver : public Observer<T>
|
||||
CallbackObserver(Callback *_objPtr, ObserverCallback _method) : objPtr(_objPtr), method(_method) {}
|
||||
|
||||
protected:
|
||||
virtual int onNotify(T arg) { return (objPtr->*method)(arg); }
|
||||
virtual int onNotify(T arg) override { return (objPtr->*method)(arg); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -104,4 +104,4 @@ template <class T> void Observer<T>::observe(Observable<T> *o)
|
||||
|
||||
observed = o;
|
||||
o->addObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
*
|
||||
* FIXME - use a lipo lookup table, the current % full is super wrong
|
||||
*/
|
||||
virtual int getBattPercentage()
|
||||
virtual int getBattPercentage() override
|
||||
{
|
||||
float v = getBattVoltage();
|
||||
|
||||
@@ -94,12 +94,16 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/**
|
||||
* The raw voltage of the batteryin millivolts or NAN if unknown
|
||||
*/
|
||||
virtual float getBattVoltage()
|
||||
virtual float getBattVoltage() override
|
||||
{
|
||||
|
||||
#ifndef ADC_MULTIPLIER
|
||||
#define ADC_MULTIPLIER 2.0
|
||||
#endif
|
||||
// Override variant or default ADC_MULTIPLIER if we have the override pref
|
||||
float operativeAdcMultiplier = radioConfig.preferences.adc_multiplier_override > 0 ?
|
||||
radioConfig.preferences.adc_multiplier_override :
|
||||
ADC_MULTIPLIER;
|
||||
|
||||
#ifdef BATTERY_PIN
|
||||
// Do not call analogRead() often.
|
||||
@@ -109,7 +113,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
uint32_t raw = analogRead(BATTERY_PIN);
|
||||
float scaled;
|
||||
#ifndef VBAT_RAW_TO_SCALED
|
||||
scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
|
||||
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
|
||||
#else
|
||||
scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h
|
||||
#endif
|
||||
@@ -127,15 +131,15 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() { return getBattPercentage() != -1; }
|
||||
virtual bool isBatteryConnect() override { return getBattPercentage() != -1; }
|
||||
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
|
||||
virtual bool isVBUSPlug() override { return getBattVoltage() > chargingVolt; }
|
||||
|
||||
/// Assume charging if we have a battery and external power is connected.
|
||||
/// we can't be smart enough to say 'full'?
|
||||
virtual bool isChargeing() { return isBatteryConnect() && isVBUSPlug(); }
|
||||
virtual bool isChargeing() override { return isBatteryConnect() && isVBUSPlug(); }
|
||||
|
||||
private:
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
@@ -149,7 +153,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
|
||||
AnalogBatteryLevel analogLevel;
|
||||
|
||||
Power::Power() : OSThread("Power") {}
|
||||
Power::Power() : OSThread("Power") {
|
||||
statusHandler = {};
|
||||
low_voltage_counter = 0;
|
||||
}
|
||||
|
||||
bool Power::analogInit()
|
||||
{
|
||||
@@ -232,18 +239,18 @@ void Power::readPowerStatus()
|
||||
}
|
||||
|
||||
// Notify any status instances that are observing us
|
||||
const PowerStatus powerStatus =
|
||||
const PowerStatus powerStatus2 =
|
||||
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
|
||||
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
|
||||
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus.getHasUSB(),
|
||||
powerStatus.getIsCharging(), powerStatus.getBatteryVoltageMv(), powerStatus.getBatteryChargePercent());
|
||||
newStatus.notifyObservers(&powerStatus);
|
||||
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
|
||||
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
||||
newStatus.notifyObservers(&powerStatus2);
|
||||
|
||||
|
||||
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
|
||||
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
|
||||
#ifdef NRF52_SERIES
|
||||
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB()){
|
||||
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()){
|
||||
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS){
|
||||
low_voltage_counter++;
|
||||
if (low_voltage_counter>3)
|
||||
@@ -254,13 +261,13 @@ void Power::readPowerStatus()
|
||||
}
|
||||
#else
|
||||
// If we have a battery at all and it is less than 10% full, force deep sleep
|
||||
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
|
||||
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
|
||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||
#endif
|
||||
} else {
|
||||
// No power sensing on this board - tell everyone else we have no idea what is happening
|
||||
const PowerStatus powerStatus = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
|
||||
newStatus.notifyObservers(&powerStatus);
|
||||
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
|
||||
newStatus.notifyObservers(&powerStatus3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ static void lsIdle()
|
||||
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
|
||||
|
||||
#ifndef NO_ESP32
|
||||
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
|
||||
|
||||
// Do we have more sleeping to do?
|
||||
if (secsSlept < getPref_ls_secs()) {
|
||||
@@ -73,14 +72,14 @@ static void lsIdle()
|
||||
// If some other service would stall sleep, don't let sleep happen yet
|
||||
if (doPreflightSleep()) {
|
||||
setLed(false); // Never leave led on while in light sleep
|
||||
wakeCause = doLightSleep(sleepTime * 1000LL);
|
||||
esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL);
|
||||
|
||||
switch (wakeCause) {
|
||||
switch (wakeCause2) {
|
||||
case ESP_SLEEP_WAKEUP_TIMER:
|
||||
// Normal case: timer expired, we should just go back to sleep ASAP
|
||||
|
||||
setLed(true); // briefly turn on led
|
||||
wakeCause = doLightSleep(1); // leave led on for 1ms
|
||||
wakeCause2 = doLightSleep(1); // leave led on for 1ms
|
||||
|
||||
secsSlept += sleepTime;
|
||||
// DEBUG_MSG("sleeping, flash led!\n");
|
||||
@@ -94,7 +93,7 @@ static void lsIdle()
|
||||
default:
|
||||
// We woke for some other reason (button press, device interrupt)
|
||||
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
|
||||
DEBUG_MSG("wakeCause %d\n", wakeCause);
|
||||
DEBUG_MSG("wakeCause2 %d\n", wakeCause2);
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
bool pressed = !digitalRead(BUTTON_PIN);
|
||||
|
||||
38
src/PowerFSMThread.h
Normal file
38
src/PowerFSMThread.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "configuration.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "main.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "power.h"
|
||||
#include "NodeDB.h"
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
/// Wrapper to convert our powerFSM stuff into a 'thread'
|
||||
class PowerFSMThread : public OSThread
|
||||
{
|
||||
public:
|
||||
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
|
||||
PowerFSMThread() : OSThread("PowerFSM") {}
|
||||
|
||||
protected:
|
||||
int32_t runOnce() override
|
||||
{
|
||||
powerFSM.run_machine();
|
||||
|
||||
/// 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();
|
||||
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
|
||||
|
||||
if (powerStatus->getHasUSB()) {
|
||||
timeLastPowered = millis();
|
||||
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 &&
|
||||
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered
|
||||
powerFSM.trigger(EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
7
src/RF95Configuration.h
Normal file
7
src/RF95Configuration.h
Normal file
@@ -0,0 +1,7 @@
|
||||
// TODO refactor this out with better radio configuration system
|
||||
#ifdef USE_RF95
|
||||
#define RF95_RESET LORA_RESET
|
||||
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
|
||||
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
|
||||
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
|
||||
#endif
|
||||
@@ -22,7 +22,7 @@ class RedirectablePrint : public Print
|
||||
volatile bool inDebugPrint = false;
|
||||
|
||||
public:
|
||||
RedirectablePrint(Print *_dest) : dest(_dest) {}
|
||||
explicit RedirectablePrint(Print *_dest) : dest(_dest) {}
|
||||
|
||||
/**
|
||||
* Set a new destination
|
||||
@@ -56,4 +56,4 @@ class NoopPrint : public Print
|
||||
/**
|
||||
* A printer that doesn't go anywhere
|
||||
*/
|
||||
extern NoopPrint noopPrint;
|
||||
extern NoopPrint noopPrint;
|
||||
|
||||
@@ -15,9 +15,9 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
|
||||
* debug serial output.
|
||||
*/
|
||||
virtual bool handleToRadio(const uint8_t *buf, size_t len);
|
||||
virtual bool handleToRadio(const uint8_t *buf, size_t len) override;
|
||||
|
||||
virtual size_t write(uint8_t c)
|
||||
virtual size_t write(uint8_t c) override
|
||||
{
|
||||
if (c == '\n') // prefix any newlines with carriage return
|
||||
RedirectablePrint::write('\r');
|
||||
@@ -27,7 +27,7 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
protected:
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected();
|
||||
virtual bool checkIsConnected() override;
|
||||
};
|
||||
|
||||
// A simple wrapper to allow non class aware code write to the console
|
||||
|
||||
@@ -2,21 +2,20 @@
|
||||
#include "NodeDB.h"
|
||||
#include "configuration.h"
|
||||
|
||||
|
||||
AirTime *airTime;
|
||||
AirTime *airTime = NULL;
|
||||
|
||||
// Don't read out of this directly. Use the helper functions.
|
||||
|
||||
|
||||
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
|
||||
{
|
||||
|
||||
// TODO: Is the airtimes array still necessary? It's now in myNodeInfo anyway
|
||||
|
||||
if (reportType == TX_LOG) {
|
||||
DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
|
||||
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
|
||||
myNodeInfo.air_period_tx[0] = myNodeInfo.air_period_tx[0] + airtime_ms;
|
||||
|
||||
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
|
||||
|
||||
} else if (reportType == RX_LOG) {
|
||||
DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
|
||||
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
|
||||
@@ -26,8 +25,8 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
|
||||
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
|
||||
}
|
||||
|
||||
uint8_t channelUtilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
|
||||
this->channelUtilization[channelUtilPeriod] = channelUtilization[channelUtilPeriod] + airtime_ms;
|
||||
// Log all airtime type for channel utilization
|
||||
this->channelUtilization[this->getPeriodUtilMinute()] = channelUtilization[this->getPeriodUtilMinute()] + airtime_ms;
|
||||
}
|
||||
|
||||
uint8_t AirTime::currentPeriodIndex()
|
||||
@@ -35,21 +34,29 @@ uint8_t AirTime::currentPeriodIndex()
|
||||
return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % PERIODS_TO_LOG);
|
||||
}
|
||||
|
||||
uint8_t AirTime::getPeriodUtilMinute() {
|
||||
return (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
|
||||
}
|
||||
|
||||
uint8_t AirTime::getPeriodUtilHour() {
|
||||
return (getSecondsSinceBoot() / 60) % MINUTES_IN_HOUR;
|
||||
}
|
||||
|
||||
void AirTime::airtimeRotatePeriod()
|
||||
{
|
||||
|
||||
if (this->airtimes.lastPeriodIndex != currentPeriodIndex()) {
|
||||
DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex());
|
||||
if (this->airtimes.lastPeriodIndex != this->currentPeriodIndex()) {
|
||||
DEBUG_MSG("Rotating airtimes to a new period = %u\n", this->currentPeriodIndex());
|
||||
|
||||
for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) {
|
||||
this->airtimes.periodTX[i + 1] = this->airtimes.periodTX[i];
|
||||
this->airtimes.periodRX[i + 1] = this->airtimes.periodRX[i];
|
||||
this->airtimes.periodRX_ALL[i + 1] = this->airtimes.periodRX_ALL[i];
|
||||
|
||||
myNodeInfo.air_period_tx[i + 1] = myNodeInfo.air_period_tx[i];
|
||||
myNodeInfo.air_period_rx[i + 1] = myNodeInfo.air_period_rx[i];
|
||||
myNodeInfo.air_period_tx[i + 1] = this->airtimes.periodTX[i];
|
||||
myNodeInfo.air_period_rx[i + 1] = this->airtimes.periodRX[i];
|
||||
}
|
||||
|
||||
|
||||
this->airtimes.periodTX[0] = 0;
|
||||
this->airtimes.periodRX[0] = 0;
|
||||
this->airtimes.periodRX_ALL[0] = 0;
|
||||
@@ -57,7 +64,7 @@ void AirTime::airtimeRotatePeriod()
|
||||
myNodeInfo.air_period_tx[0] = 0;
|
||||
myNodeInfo.air_period_rx[0] = 0;
|
||||
|
||||
this->airtimes.lastPeriodIndex = currentPeriodIndex();
|
||||
this->airtimes.lastPeriodIndex = this->currentPeriodIndex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,25 +107,53 @@ float AirTime::channelUtilizationPercent()
|
||||
return (float(sum) / float(CHANNEL_UTILIZATION_PERIODS * 10 * 1000)) * 100;
|
||||
}
|
||||
|
||||
AirTime::AirTime() : concurrency::OSThread("AirTime") {}
|
||||
float AirTime::utilizationTXPercent()
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
|
||||
sum += this->utilizationTX[i];
|
||||
}
|
||||
|
||||
return (float(sum) / float(MS_IN_HOUR)) * 100;
|
||||
}
|
||||
|
||||
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
|
||||
}
|
||||
|
||||
int32_t AirTime::runOnce()
|
||||
{
|
||||
secSinceBoot++;
|
||||
|
||||
uint8_t utilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
|
||||
uint8_t utilPeriod = this->getPeriodUtilMinute();
|
||||
uint8_t utilPeriodTX = this->getPeriodUtilHour();
|
||||
|
||||
if (firstTime) {
|
||||
airtimeRotatePeriod();
|
||||
|
||||
// Init utilizationTX window to all 0
|
||||
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
|
||||
this->utilizationTX[i] = 0;
|
||||
}
|
||||
|
||||
// Init channelUtilization window to all 0
|
||||
for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) {
|
||||
this->channelUtilization[i] = 0;
|
||||
}
|
||||
|
||||
// Init airtime windows to all 0
|
||||
for (int i = 0; i < myNodeInfo.air_period_rx_count; i++) {
|
||||
this->airtimes.periodTX[i] = 0;
|
||||
this->airtimes.periodRX[i] = 0;
|
||||
this->airtimes.periodRX_ALL[i] = 0;
|
||||
|
||||
// myNodeInfo.air_period_tx[i] = 0;
|
||||
// myNodeInfo.air_period_rx[i] = 0;
|
||||
}
|
||||
|
||||
firstTime = false;
|
||||
lastUtilPeriod = utilPeriod;
|
||||
|
||||
} else {
|
||||
this->airtimeRotatePeriod();
|
||||
|
||||
// Reset the channelUtilization window when we roll over
|
||||
if (lastUtilPeriod != utilPeriod) {
|
||||
@@ -127,9 +162,26 @@ int32_t AirTime::runOnce()
|
||||
this->channelUtilization[utilPeriod] = 0;
|
||||
}
|
||||
|
||||
if (lastUtilPeriodTX != utilPeriodTX) {
|
||||
lastUtilPeriodTX = utilPeriodTX;
|
||||
|
||||
this->utilizationTX[utilPeriodTX] = 0;
|
||||
}
|
||||
|
||||
// Update channel_utilization every second.
|
||||
myNodeInfo.channel_utilization = airTime->channelUtilizationPercent();
|
||||
}
|
||||
|
||||
// Update channel_utilization every second.
|
||||
myNodeInfo.air_util_tx = airTime->utilizationTXPercent();
|
||||
}
|
||||
/*
|
||||
DEBUG_MSG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
|
||||
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
|
||||
DEBUG_MSG(
|
||||
"%d,", this->utilizationTX[i]
|
||||
);
|
||||
}
|
||||
DEBUG_MSG("\n");
|
||||
*/
|
||||
return (1000 * 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,10 @@
|
||||
|
||||
#define CHANNEL_UTILIZATION_PERIODS 6
|
||||
#define SECONDS_PER_PERIOD 3600
|
||||
#define PERIODS_TO_LOG 24
|
||||
#define PERIODS_TO_LOG 8
|
||||
#define MINUTES_IN_HOUR 60
|
||||
#define SECONDS_IN_MINUTE 60
|
||||
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
|
||||
|
||||
|
||||
enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
|
||||
@@ -43,9 +46,12 @@ class AirTime : private concurrency::OSThread
|
||||
|
||||
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
|
||||
float channelUtilizationPercent();
|
||||
uint32_t channelUtilization[CHANNEL_UTILIZATION_PERIODS];
|
||||
float utilizationTXPercent();
|
||||
|
||||
float UtilizationPercentTX();
|
||||
uint32_t channelUtilization[CHANNEL_UTILIZATION_PERIODS] = {0};
|
||||
uint32_t utilizationTX[MINUTES_IN_HOUR] = {0};
|
||||
|
||||
uint8_t currentPeriodIndex();
|
||||
void airtimeRotatePeriod();
|
||||
uint8_t getPeriodsToLog();
|
||||
uint32_t getSecondsPerPeriod();
|
||||
@@ -55,6 +61,7 @@ class AirTime : private concurrency::OSThread
|
||||
private:
|
||||
bool firstTime = true;
|
||||
uint8_t lastUtilPeriod = 0;
|
||||
uint8_t lastUtilPeriodTX = 0;
|
||||
uint32_t secSinceBoot = 0;
|
||||
|
||||
struct airtimeStruct {
|
||||
@@ -64,8 +71,12 @@ class AirTime : private concurrency::OSThread
|
||||
uint8_t lastPeriodIndex;
|
||||
} airtimes;
|
||||
|
||||
uint8_t getPeriodUtilMinute();
|
||||
uint8_t getPeriodUtilHour();
|
||||
uint8_t currentPeriodIndex();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern AirTime *airTime;
|
||||
extern AirTime *airTime;
|
||||
|
||||
@@ -13,4 +13,5 @@ enum class Cmd {
|
||||
STOP_BLUETOOTH_PIN_SCREEN,
|
||||
STOP_BOOT_SCREEN,
|
||||
PRINT,
|
||||
START_SHUTDOWN_SCREEN,
|
||||
};
|
||||
@@ -7,9 +7,8 @@
|
||||
namespace concurrency
|
||||
{
|
||||
|
||||
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS()
|
||||
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS() : semaphore(xSemaphoreCreateBinary())
|
||||
{
|
||||
semaphore = xSemaphoreCreateBinary();
|
||||
assert(semaphore);
|
||||
}
|
||||
|
||||
@@ -38,4 +37,4 @@ IRAM_ATTR void BinarySemaphoreFreeRTOS::giveFromISR(BaseType_t *pxHigherPriority
|
||||
|
||||
} // namespace concurrency
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -6,9 +6,8 @@ namespace concurrency
|
||||
{
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
Lock::Lock()
|
||||
Lock::Lock() : handle(xSemaphoreCreateBinary())
|
||||
{
|
||||
handle = xSemaphoreCreateBinary();
|
||||
assert(handle);
|
||||
assert(xSemaphoreGive(handle));
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace concurrency {
|
||||
class LockGuard
|
||||
{
|
||||
public:
|
||||
LockGuard(Lock *lock);
|
||||
explicit LockGuard(Lock *lock);
|
||||
~LockGuard();
|
||||
|
||||
LockGuard(const LockGuard &) = delete;
|
||||
|
||||
@@ -39,7 +39,7 @@ class NotifiedWorkerThread : public OSThread
|
||||
virtual void onNotify(uint32_t notification) = 0;
|
||||
|
||||
/// just calls checkNotification()
|
||||
virtual int32_t runOnce();
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
/// Sometimes we might want to check notifications independently of when our thread was getting woken up (i.e. if we are about to change
|
||||
/// radio transmit/receive modes we want to handle any pending interrupts first). You can call this method and if any notifications are currently
|
||||
|
||||
@@ -18,7 +18,7 @@ class Periodic : public OSThread
|
||||
Periodic(const char *name, int32_t (*_callback)()) : OSThread(name), callback(_callback) {}
|
||||
|
||||
protected:
|
||||
int32_t runOnce() { return callback(); }
|
||||
int32_t runOnce() override { return callback(); }
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
|
||||
@@ -45,10 +45,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled)
|
||||
// we don't support jtag on the ttgo - access to gpio 12 is a PITA
|
||||
#ifdef ARDUINO_HELTEC_WIFI_LORA_32_V2
|
||||
//#define USE_JTAG
|
||||
#endif
|
||||
|
||||
#define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found
|
||||
|
||||
/// Convert a preprocessor name into a quoted string
|
||||
@@ -88,18 +84,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define BUTTON_PIN_TOUCH PIN_BUTTON_TOUCH
|
||||
#endif
|
||||
|
||||
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
|
||||
#elif defined(CubeCell_BoardPlus)
|
||||
|
||||
//
|
||||
// Standard definitions for CubeCell targets
|
||||
//
|
||||
|
||||
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
|
||||
|
||||
#define LED_PIN -1 // FIXME totally bogus
|
||||
#define BUTTON_PIN -1
|
||||
|
||||
#else
|
||||
|
||||
//
|
||||
@@ -169,338 +153,59 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TBEAM
|
||||
|
||||
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
||||
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
|
||||
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
|
||||
//#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed. Does anyone use this? It is not documented anywhere.
|
||||
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
|
||||
|
||||
#define LED_INVERTED 1
|
||||
#define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
|
||||
|
||||
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||
// not found then probe for SX1262
|
||||
#define USE_RF95
|
||||
#define USE_SX1262
|
||||
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 23
|
||||
#define LORA_DIO1 33 // SX1262 IRQ
|
||||
#define LORA_DIO2 32 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_E22 // Not really an E22 but TTGO seems to be trying to clone that
|
||||
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
|
||||
// code)
|
||||
#endif
|
||||
|
||||
// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
|
||||
// and waking from light sleep
|
||||
// #define PMU_IRQ 35
|
||||
#define AXP192_SLAVE_ADDRESS 0x34
|
||||
|
||||
#elif defined(TBEAM_V07)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TBEAM0p7
|
||||
|
||||
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
||||
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
|
||||
#define BUTTON_PIN 39
|
||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 23
|
||||
#define LORA_DIO1 33 // Not really used
|
||||
#define LORA_DIO2 32 // Not really used
|
||||
|
||||
// This board has different GPS pins than all other boards
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 12
|
||||
#define GPS_TX_PIN 15
|
||||
|
||||
#elif defined(DIY_V1)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_DIY_V1
|
||||
|
||||
// For OLED LCD
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
|
||||
// GPS
|
||||
#undef GPS_RX_PIN
|
||||
#define GPS_RX_PIN 15
|
||||
//#undef GPS_TX_PIN
|
||||
//#define GPS_TX_PIN 12 // not connected
|
||||
|
||||
#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam
|
||||
#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Plugin (#975).
|
||||
#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets)
|
||||
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262/SX1268 module
|
||||
#define LORA_RESET 23 // RST for SX1276, and for SX1262/SX1268
|
||||
#define LORA_DIO1 33 // IRQ for SX1262/SX1268
|
||||
#define LORA_DIO2 32 // BUSY for SX1262/SX1268
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS 18
|
||||
|
||||
// supported modules list
|
||||
#define USE_SX1262
|
||||
#define USE_SX1268
|
||||
#define USE_LLCC68
|
||||
|
||||
// common pinouts for SX126X modules
|
||||
#define SX126X_CS 18 // NSS for SX126X
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_RXEN 14
|
||||
#define SX126X_TXEN 13
|
||||
|
||||
#ifdef EBYTE_E22
|
||||
// Internally the TTGO module hooks the SX126x-DIO2 in to control the TX/RX switch
|
||||
// (which is the default for the sx1262interface code)
|
||||
#define SX126X_E22
|
||||
#endif
|
||||
#elif defined(RAK_11200)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_RAK11200
|
||||
|
||||
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
|
||||
|
||||
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
|
||||
// Tested on Neo6m module.
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 37
|
||||
|
||||
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 15
|
||||
#endif
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#ifndef USE_JTAG
|
||||
#define LORA_RESET 14
|
||||
#endif
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
|
||||
#define ADC_MULTIPLIER 3.2
|
||||
|
||||
#ifdef HELTEC_V2_0
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V2_0
|
||||
|
||||
#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HELTEC_V2_1
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V2_1
|
||||
|
||||
#define BATTERY_PIN 37 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
|
||||
|
||||
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
|
||||
// Tested on Neo6m module.
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 37
|
||||
|
||||
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 15
|
||||
#endif
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#ifndef USE_JTAG
|
||||
#define LORA_RESET 14
|
||||
#endif
|
||||
#define LORA_DIO1 33 // Not really used
|
||||
#define LORA_DIO2 32 // Not really used
|
||||
|
||||
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
|
||||
#define ADC_MULTIPLIER 3.2
|
||||
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V1
|
||||
|
||||
#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#elif defined(TLORA_V1)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
|
||||
#define HW_VENDOR HardwareModel_TLORA_V1
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 37
|
||||
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 15
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
// #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 2 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||
#define BUTTON_NEED_PULLUP
|
||||
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Plugin.
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
#elif defined(TLORA_V2)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TLORA_V2
|
||||
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 13 // per @eugene
|
||||
|
||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#define I2C_SDA 21 // I2C pins for this board
|
||||
#define I2C_SCL 22
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN \
|
||||
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
|
||||
// between this pin and ground
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
#elif defined(TLORA_V1_3)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TLORA_V1_1p3
|
||||
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 13 // per @eugene
|
||||
|
||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 15
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 36
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
#elif defined(TLORA_V2_1_16)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TLORA_V2_1_1p6
|
||||
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 15 // per @der_bear on the forum, 36 is incorrect for this board type and 15 is a better pick
|
||||
#define GPS_TX_PIN 13
|
||||
|
||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#define I2C_SDA 21 // I2C pins for this board
|
||||
#define I2C_SCL 22
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 12 // If defined, this will be used for user button presses,
|
||||
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
#elif defined(GENIEBLOCKS)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_GENIEBLOCKS
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 5
|
||||
#define GPS_TX_PIN 18
|
||||
#define GPS_RESET_N 10
|
||||
#define GPS_EXTINT 23 // On MAX-M8 module pin name is EXTINT. On L70 module pin name is STANDBY.
|
||||
|
||||
#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
#define BATTERY_EN_PIN 14 // Voltage voltage divider enable pin connected to mosfet
|
||||
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 2
|
||||
|
||||
#define LED_PIN 12 // If defined we will blink this LED
|
||||
//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen -->
|
||||
// Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal
|
||||
// pull-ups or pull-down resistors.
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 38 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 9
|
||||
|
||||
#define RF95_SCK 22
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 13
|
||||
#define RF95_NSS 21
|
||||
#elif defined(PRIVATE_HW)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_PRIVATE_HW
|
||||
|
||||
#endif
|
||||
|
||||
@@ -533,100 +238,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#define HW_VENDOR HardwareModel_PORTDUINO
|
||||
|
||||
#define USE_SIM_RADIO
|
||||
|
||||
// Pine64 uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||
// not found then probe for SX1262. Currently the RF95 code is disabled because I think the RF95 module won't need to ship.
|
||||
// #define USE_RF95
|
||||
#define USE_SX1262
|
||||
|
||||
// Fake SPI device selections
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
|
||||
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 33 // SX1262 IRQ, called DIO0 on pinelora schematic, pin 7 on ch341f "ack" - FIXME, enable hwints in linux
|
||||
#define LORA_DIO2 32 // SX1262 BUSY, actually connected to "DIO5" on pinelora schematic, pin 8 on ch341f "slct"
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX126X_CS 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
// HOPE RFM90 does not have a TCXO therefore not SX126X_E22
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// DEBUG LED
|
||||
#ifndef LED_INVERTED
|
||||
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
|
||||
#endif
|
||||
|
||||
#ifdef USE_RF95
|
||||
#define RF95_RESET LORA_RESET
|
||||
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
|
||||
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
|
||||
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// DEBUG
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#ifdef CONSOLE_MAX_BAUD
|
||||
#define SERIAL_BAUD CONSOLE_MAX_BAUD
|
||||
#else
|
||||
#define SERIAL_BAUD 921600 // Serial debug baud rate
|
||||
#endif
|
||||
|
||||
#include "SerialConsole.h"
|
||||
|
||||
#define DEBUG_PORT (*console) // Serial debug port
|
||||
|
||||
// What platforms should use SEGGER?
|
||||
#ifdef NRF52_SERIES
|
||||
|
||||
// Always include the SEGGER code on NRF52 - because useful for debugging
|
||||
#include "SEGGER_RTT.h"
|
||||
|
||||
// The channel we send stdout data to
|
||||
#define SEGGER_STDOUT_CH 0
|
||||
|
||||
// Debug printing to segger console
|
||||
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
|
||||
|
||||
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
|
||||
// use SEGGER for debug output
|
||||
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
|
||||
// No serial ports on this board - ONLY use segger in memory console
|
||||
#define USE_SEGGER
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
|
||||
#endif
|
||||
|
||||
#ifdef USE_SEGGER
|
||||
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
#ifdef DEBUG_PORT
|
||||
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_MSG(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// AXP192 (Rev1-specific options)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define GPS_POWER_CTRL_CH 3
|
||||
#define LORA_POWER_CTRL_CH 2
|
||||
|
||||
// Default Bluetooth PIN
|
||||
#define defaultBLEPin 123456
|
||||
#include "variant.h"
|
||||
#include "RF95Configuration.h"
|
||||
#include "DebugConfiguration.h"
|
||||
19
src/debug/axpDebug.h
Normal file
19
src/debug/axpDebug.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#if 0
|
||||
// Turn off for now
|
||||
uint32_t axpDebugRead()
|
||||
{
|
||||
axp.debugCharging();
|
||||
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
|
||||
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
|
||||
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
|
||||
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
|
||||
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
|
||||
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
|
||||
DEBUG_MSG("is charging %d\n", axp.isChargeing());
|
||||
|
||||
return 30 * 1000;
|
||||
}
|
||||
|
||||
Periodic axpDebugOutput(axpDebugRead);
|
||||
axpDebugOutput.setup();
|
||||
#endif
|
||||
44
src/debug/i2cScan.h
Normal file
44
src/debug/i2cScan.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "../configuration.h"
|
||||
#include "../main.h"
|
||||
#include <Wire.h>
|
||||
|
||||
#ifndef NO_WIRE
|
||||
void scanI2Cdevice(void)
|
||||
{
|
||||
byte err, addr;
|
||||
int nDevices = 0;
|
||||
for (addr = 1; addr < 127; addr++) {
|
||||
Wire.beginTransmission(addr);
|
||||
err = Wire.endTransmission();
|
||||
if (err == 0) {
|
||||
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
|
||||
|
||||
nDevices++;
|
||||
|
||||
if (addr == SSD1306_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("ssd1306 display found\n");
|
||||
}
|
||||
if (addr == ST7567_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("st7567 display found\n");
|
||||
}
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
if (addr == AXP192_SLAVE_ADDRESS) {
|
||||
axp192_found = true;
|
||||
DEBUG_MSG("axp192 PMU found\n");
|
||||
}
|
||||
#endif
|
||||
} else if (err == 4) {
|
||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
DEBUG_MSG("No I2C devices found\n");
|
||||
else
|
||||
DEBUG_MSG("done\n");
|
||||
}
|
||||
#else
|
||||
void scanI2Cdevice(void) {}
|
||||
#endif
|
||||
@@ -58,7 +58,7 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_BLOCKSIZE 512
|
||||
#define MAX_BLOCKSIZE_FOR_BT 512
|
||||
|
||||
/// Handle writes to data
|
||||
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
@@ -66,7 +66,7 @@ int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
|
||||
concurrency::LockGuard g(updateLock);
|
||||
|
||||
static uint8_t
|
||||
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
|
||||
data[MAX_BLOCKSIZE_FOR_BT]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
|
||||
|
||||
uint16_t len = 0;
|
||||
|
||||
@@ -104,8 +104,8 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble
|
||||
} else {
|
||||
if (Update.end()) {
|
||||
if (update_region == U_SPIFFS) {
|
||||
DEBUG_MSG("SPIFFS updated!\n");
|
||||
nodeDB.saveToDisk(); // Since we just wiped spiffs, we need to save our current state
|
||||
DEBUG_MSG("Filesystem updated!\n");
|
||||
nodeDB.saveToDisk(); // Since we just wiped the filesystem, we need to save our current state
|
||||
} else {
|
||||
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
|
||||
rebootAtMsec = millis() + 5000;
|
||||
|
||||
@@ -32,7 +32,7 @@ class ESP32CryptoEngine : public CryptoEngine
|
||||
* @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the
|
||||
* provided pointer)
|
||||
*/
|
||||
virtual void setKey(const CryptoKey &k)
|
||||
virtual void setKey(const CryptoKey &k) override
|
||||
{
|
||||
CryptoEngine::setKey(k);
|
||||
|
||||
@@ -47,7 +47,7 @@ class ESP32CryptoEngine : public CryptoEngine
|
||||
*
|
||||
* @param bytes is updated in place
|
||||
*/
|
||||
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
|
||||
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
|
||||
{
|
||||
if (key.length > 0) {
|
||||
uint8_t stream_block[16];
|
||||
@@ -66,7 +66,7 @@ class ESP32CryptoEngine : public CryptoEngine
|
||||
}
|
||||
}
|
||||
|
||||
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
|
||||
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
|
||||
{
|
||||
// DEBUG_MSG("ESP32 decrypt!\n");
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
*/
|
||||
class SimpleAllocator
|
||||
{
|
||||
uint8_t bytes[POOL_SIZE];
|
||||
uint8_t bytes[POOL_SIZE] = {};
|
||||
|
||||
uint32_t nextFree;
|
||||
uint32_t nextFree = 0;
|
||||
|
||||
public:
|
||||
SimpleAllocator();
|
||||
@@ -37,6 +37,6 @@ void *operator new(size_t size, SimpleAllocator &p);
|
||||
*/
|
||||
class AllocatorScope {
|
||||
public:
|
||||
AllocatorScope(SimpleAllocator &a);
|
||||
explicit AllocatorScope(SimpleAllocator &a);
|
||||
~AllocatorScope();
|
||||
};
|
||||
|
||||
@@ -11,10 +11,10 @@ class Air530GPS : public NMEAGPS
|
||||
{
|
||||
protected:
|
||||
/// If possible force the GPS into sleep/low power mode
|
||||
virtual void sleep();
|
||||
virtual void sleep() override;
|
||||
|
||||
/// wake the GPS into normal operation mode
|
||||
virtual void wake();
|
||||
virtual void wake() override;
|
||||
|
||||
private:
|
||||
/// Send a NMEA cmd with checksum
|
||||
|
||||
@@ -145,7 +145,7 @@ class GPS : private concurrency::OSThread
|
||||
*/
|
||||
void publishUpdate();
|
||||
|
||||
virtual int32_t runOnce();
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
// Creates an instance of the GPS class.
|
||||
|
||||
@@ -171,7 +171,7 @@ void GeoCoord::latLongToMGRS(const double lat, const double lon, MGRS &mgrs) {
|
||||
* Based on: https://www.movable-type.co.uk/scripts/latlong-os-gridref.html
|
||||
*/
|
||||
void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) {
|
||||
char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR
|
||||
const char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR
|
||||
double a = 6377563.396; // Airy 1830 semi-major axis
|
||||
double b = 6356256.909; // Airy 1830 semi-minor axis
|
||||
double f0 = 0.9996012717; // National Grid point scale factor on the central meridian
|
||||
@@ -419,12 +419,12 @@ float GeoCoord::rangeRadiansToMeters(double range_radians) {
|
||||
}
|
||||
|
||||
// Find distance from point to passed in point
|
||||
int32_t GeoCoord::distanceTo(GeoCoord pointB) {
|
||||
int32_t GeoCoord::distanceTo(const GeoCoord& pointB) {
|
||||
return latLongToMeter(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
|
||||
}
|
||||
|
||||
// Find bearing from point to passed in point
|
||||
int32_t GeoCoord::bearingTo(GeoCoord pointB) {
|
||||
int32_t GeoCoord::bearingTo(const GeoCoord& pointB) {
|
||||
return bearing(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
|
||||
}
|
||||
|
||||
@@ -447,4 +447,4 @@ std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range
|
||||
|
||||
return std::make_shared<GeoCoord>(double(lat), double(lon), this->getAltitude());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,11 @@ class GeoCoord {
|
||||
int32_t _longitude = 0;
|
||||
int32_t _altitude = 0;
|
||||
|
||||
DMS _dms;
|
||||
UTM _utm;
|
||||
MGRS _mgrs;
|
||||
OSGR _osgr;
|
||||
OLC _olc;
|
||||
DMS _dms = {};
|
||||
UTM _utm = {};
|
||||
MGRS _mgrs = {};
|
||||
OSGR _osgr = {};
|
||||
OLC _olc = {};
|
||||
|
||||
bool _dirty = true;
|
||||
|
||||
@@ -119,8 +119,8 @@ class GeoCoord {
|
||||
static float rangeMetersToRadians(double range_meters);
|
||||
|
||||
// Point to point conversions
|
||||
int32_t distanceTo(GeoCoord pointB);
|
||||
int32_t bearingTo(GeoCoord pointB);
|
||||
int32_t distanceTo(const GeoCoord& pointB);
|
||||
int32_t bearingTo(const GeoCoord& pointB);
|
||||
std::shared_ptr<GeoCoord> pointAtDistance(double bearing, double range);
|
||||
|
||||
// Lat lon alt getters
|
||||
|
||||
@@ -23,14 +23,14 @@ class NMEAGPS : public GPS
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual bool setupGPS();
|
||||
virtual bool setupGPS() override;
|
||||
|
||||
protected:
|
||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
||||
*
|
||||
* Return true if we received a valid message from the GPS
|
||||
*/
|
||||
virtual bool whileIdle();
|
||||
virtual bool whileIdle() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
@@ -38,7 +38,7 @@ class NMEAGPS : public GPS
|
||||
*
|
||||
* @return true if we've acquired a time
|
||||
*/
|
||||
virtual bool lookForTime();
|
||||
virtual bool lookForTime() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
@@ -46,7 +46,7 @@ class NMEAGPS : public GPS
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation();
|
||||
virtual bool lookForLocation() override;
|
||||
|
||||
virtual bool hasLock();
|
||||
virtual bool hasLock() override;
|
||||
};
|
||||
|
||||
@@ -22,22 +22,22 @@ class UBloxGPS : public GPS
|
||||
*
|
||||
* @return true for success
|
||||
*/
|
||||
bool factoryReset();
|
||||
bool factoryReset() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns true if we succeeded
|
||||
*/
|
||||
virtual bool setupGPS();
|
||||
virtual bool setupGPS() override;
|
||||
|
||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
||||
*
|
||||
* Return true if we received a valid message from the GPS
|
||||
*/
|
||||
virtual bool whileIdle();
|
||||
virtual bool whileIdle() override;
|
||||
|
||||
/** Idle processing while GPS is looking for lock */
|
||||
virtual void whileActive();
|
||||
virtual void whileActive() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
@@ -45,7 +45,7 @@ class UBloxGPS : public GPS
|
||||
*
|
||||
* @return true if we've acquired a time
|
||||
*/
|
||||
virtual bool lookForTime();
|
||||
virtual bool lookForTime() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
@@ -53,12 +53,12 @@ class UBloxGPS : public GPS
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation();
|
||||
virtual bool hasLock();
|
||||
virtual bool lookForLocation() override;
|
||||
virtual bool hasLock() override;
|
||||
|
||||
/// If possible force the GPS into sleep/low power mode
|
||||
virtual void sleep();
|
||||
virtual void wake();
|
||||
virtual void sleep() override;
|
||||
virtual void wake() override;
|
||||
|
||||
private:
|
||||
/// Attempt to connect to our GPS, returns false if no gps is present
|
||||
|
||||
@@ -9,14 +9,45 @@
|
||||
#define COLORED GxEPD_BLACK
|
||||
#define UNCOLORED GxEPD_WHITE
|
||||
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67
|
||||
#elif defined(RAK4630)
|
||||
|
||||
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_B74
|
||||
|
||||
//4.2 inch 300x400 - GxEPD2_420_M01
|
||||
//#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
|
||||
|
||||
//2.9 inch 296x128 - GxEPD2_290_T5D
|
||||
//#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
|
||||
|
||||
//1.54 inch 200x200 - GxEPD2_154_M09
|
||||
//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||
|
||||
#endif
|
||||
|
||||
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
||||
|
||||
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
|
||||
{
|
||||
#if defined(TTGO_T_ECHO)
|
||||
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
|
||||
#elif defined(RAK4630)
|
||||
|
||||
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
|
||||
setGeometry(GEOMETRY_RAWMODE, 250, 122);
|
||||
|
||||
//GxEPD2_420_M01
|
||||
//setGeometry(GEOMETRY_RAWMODE, 300, 400);
|
||||
|
||||
//GxEPD2_290_T5D
|
||||
//setGeometry(GEOMETRY_RAWMODE, 296, 128);
|
||||
|
||||
//GxEPD2_154_M09
|
||||
//setGeometry(GEOMETRY_RAWMODE, 200, 200);
|
||||
|
||||
#endif
|
||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
||||
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
||||
}
|
||||
@@ -40,8 +71,8 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
|
||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
|
||||
for (uint8_t y = 0; y < displayHeight; y++) {
|
||||
for (uint8_t x = 0; x < displayWidth; x++) {
|
||||
for (uint64_t y = 0; y < displayHeight; y++) {
|
||||
for (uint64_t x = 0; x < displayWidth; x++) {
|
||||
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto b = buffer[x + (y / 8) * displayWidth];
|
||||
@@ -50,9 +81,28 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG("Updating eink... ");
|
||||
#if defined(TTGO_T_ECHO)
|
||||
DEBUG_MSG("Updating T-ECHO E-Paper... ");
|
||||
#elif defined(RAK4630)
|
||||
DEBUG_MSG("Updating RAK4361_5005 E-Paper... ");
|
||||
#endif
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
// ePaper.Reset(); // wake the screen from sleep
|
||||
adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||
#elif defined(RAK4630)
|
||||
|
||||
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
|
||||
adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||
|
||||
//Only enable for e-Paper with support for partial updates and comment out above adafruitDisplay->display(false);
|
||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
||||
// 4.2 inch 300x400 - GxEPD2_420_M01
|
||||
//adafruitDisplay->nextPage();
|
||||
|
||||
#endif
|
||||
|
||||
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
||||
adafruitDisplay->hibernate();
|
||||
DEBUG_MSG("done\n");
|
||||
@@ -97,14 +147,33 @@ bool EInkDisplay::connect()
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS,
|
||||
PIN_EINK_DC,
|
||||
PIN_EINK_RES,
|
||||
PIN_EINK_BUSY, SPI1);
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
|
||||
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
}
|
||||
#elif defined(RAK4630)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
|
||||
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
|
||||
adafruitDisplay->setRotation(3);
|
||||
//For 1.54, 2.9 and 4.2
|
||||
//adafruitDisplay->setRotation(1);
|
||||
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//adafruitDisplay->setFullWindow();
|
||||
//adafruitDisplay->fillScreen(UNCOLORED);
|
||||
//adafruitDisplay->drawCircle(100, 100, 20, COLORED);
|
||||
|
||||
@@ -25,7 +25,7 @@ class EInkDisplay : public OLEDDisplay
|
||||
EInkDisplay(uint8_t address, int sda, int scl);
|
||||
|
||||
// Write the buffer to the display memory (for eink we only do this occasionally)
|
||||
virtual void display(void);
|
||||
virtual void display(void) override;
|
||||
|
||||
/**
|
||||
* Force a display update if we haven't drawn within the specified msecLimit
|
||||
@@ -36,13 +36,13 @@ class EInkDisplay : public OLEDDisplay
|
||||
|
||||
protected:
|
||||
// the header size of the buffer used, e.g. for the SPI command header
|
||||
virtual int getBufferOffset(void) { return 0; }
|
||||
virtual int getBufferOffset(void) override { return 0; }
|
||||
|
||||
// Send a command to the display (low level function)
|
||||
virtual void sendCommand(uint8_t com);
|
||||
virtual void sendCommand(uint8_t com) override;
|
||||
|
||||
// Connect to the display
|
||||
virtual bool connect();
|
||||
virtual bool connect() override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -26,14 +26,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "Screen.h"
|
||||
#include "fonts.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/Channels.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
@@ -68,9 +67,9 @@ uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
|
||||
// Threshold values for the GPS lock accuracy bar display
|
||||
uint32_t dopThresholds[5] = {2000, 1000, 500, 200, 100};
|
||||
|
||||
// At some point, we're going to ask all of the plugins if they would like to display a screen frame
|
||||
// we'll need to hold onto pointers for the plugins that can draw a frame.
|
||||
std::vector<MeshPlugin *> pluginFrames;
|
||||
// At some point, we're going to ask all of the modules if they would like to display a screen frame
|
||||
// we'll need to hold onto pointers for the modules that can draw a frame.
|
||||
std::vector<MeshPlugin *> moduleFrames;
|
||||
|
||||
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||
static char ourId[5];
|
||||
@@ -177,9 +176,9 @@ static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
||||
}
|
||||
#endif
|
||||
|
||||
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
uint8_t plugin_frame;
|
||||
uint8_t module_frame;
|
||||
// there's a little but in the UI transition code
|
||||
// where it invokes the function at the correct offset
|
||||
// in the array of "drawScreen" functions; however,
|
||||
@@ -188,14 +187,14 @@ static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
||||
if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) {
|
||||
// if we're transitioning from the end of the frame list back around to the first
|
||||
// frame, then we want this to be `0`
|
||||
plugin_frame = state->transitionFrameTarget;
|
||||
module_frame = state->transitionFrameTarget;
|
||||
} else {
|
||||
// otherwise, just display the plugin frame that's aligned with the current frame
|
||||
plugin_frame = state->currentFrame;
|
||||
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
|
||||
// otherwise, just display the module frame that's aligned with the current frame
|
||||
module_frame = state->currentFrame;
|
||||
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", module_frame);
|
||||
}
|
||||
// DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
|
||||
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
|
||||
// DEBUG_MSG("Drawing Module Frame %d\n\n", module_frame);
|
||||
MeshPlugin &pi = *moduleFrames.at(module_frame);
|
||||
pi.drawFrame(display, state, x, y);
|
||||
}
|
||||
|
||||
@@ -219,6 +218,14 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
display->drawString(64 + x, 48 + y, buf);
|
||||
}
|
||||
|
||||
static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, 26 + y, "Shutting down...");
|
||||
}
|
||||
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
@@ -252,11 +259,11 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
|
||||
}
|
||||
|
||||
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward plugin are enabled
|
||||
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||
static bool shouldDrawMessage(const MeshPacket *packet)
|
||||
{
|
||||
return packet->from != 0 && !radioConfig.preferences.range_test_plugin_enabled &&
|
||||
!radioConfig.preferences.store_forward_plugin_enabled;
|
||||
return packet->from != 0 && !radioConfig.preferences.range_test_module_enabled &&
|
||||
!radioConfig.preferences.store_forward_module_enabled;
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
@@ -442,10 +449,10 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
|
||||
if (gpsFormat == GpsCoordinateFormat_GpsFormatDec) { // Decimal Degrees
|
||||
sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7);
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatUTM) { // Universal Transverse Mercator
|
||||
sprintf(coordinateLine, "%2i%1c %06i %07i", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
|
||||
sprintf(coordinateLine, "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
|
||||
geoCoord.getUTMEasting(), geoCoord.getUTMNorthing());
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatMGRS) { // Military Grid Reference System
|
||||
sprintf(coordinateLine, "%2i%1c %1c%1c %05i %05i", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(),
|
||||
sprintf(coordinateLine, "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(),
|
||||
geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(), geoCoord.getMGRSEasting(),
|
||||
geoCoord.getMGRSNorthing());
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOLC) { // Open Location Code
|
||||
@@ -454,7 +461,7 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
|
||||
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region
|
||||
sprintf(coordinateLine, "%s", "Out of Boundary");
|
||||
else
|
||||
sprintf(coordinateLine, "%1c%1c %05i %05i", geoCoord.getOSGRE100k(), geoCoord.getOSGRN100k(),
|
||||
sprintf(coordinateLine, "%1c%1c %05u %05u", geoCoord.getOSGRE100k(), geoCoord.getOSGRN100k(),
|
||||
geoCoord.getOSGREasting(), geoCoord.getOSGRNorthing());
|
||||
}
|
||||
|
||||
@@ -472,9 +479,9 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
|
||||
} else {
|
||||
char latLine[22];
|
||||
char lonLine[22];
|
||||
sprintf(latLine, "%2i° %2i' %2.4f\" %1c", geoCoord.getDMSLatDeg(), geoCoord.getDMSLatMin(), geoCoord.getDMSLatSec(),
|
||||
sprintf(latLine, "%2i° %2i' %2u\" %1c", geoCoord.getDMSLatDeg(), geoCoord.getDMSLatMin(), geoCoord.getDMSLatSec(),
|
||||
geoCoord.getDMSLatCP());
|
||||
sprintf(lonLine, "%3i° %2i' %2.4f\" %1c", geoCoord.getDMSLonDeg(), geoCoord.getDMSLonMin(), geoCoord.getDMSLonSec(),
|
||||
sprintf(lonLine, "%3i° %2i' %2u\" %1c", geoCoord.getDMSLonDeg(), geoCoord.getDMSLonMin(), geoCoord.getDMSLonSec(),
|
||||
geoCoord.getDMSLonCP());
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(latLine))) / 2, y - FONT_HEIGHT_SMALL * 1, latLine);
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(lonLine))) / 2, y, lonLine);
|
||||
@@ -644,7 +651,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
|
||||
static char distStr[20];
|
||||
strcpy(distStr, "? km"); // might not have location data
|
||||
float headingRadian;
|
||||
NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
|
||||
@@ -672,7 +678,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
// it. currently we don't do this and instead draw north up only.
|
||||
float bearingToOther =
|
||||
GeoCoord::bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
headingRadian = bearingToOther - myHeading;
|
||||
float headingRadian = bearingToOther - myHeading;
|
||||
drawNodeHeading(display, compassX, compassY, headingRadian);
|
||||
}
|
||||
}
|
||||
@@ -818,8 +824,11 @@ void Screen::setup()
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
if (textMessagePlugin)
|
||||
textMessageObserver.observe(textMessagePlugin);
|
||||
if (textMessageModule)
|
||||
textMessageObserver.observe(textMessageModule);
|
||||
|
||||
// Modules can notify screen about refresh
|
||||
MeshPlugin::observeUIEvents(&uiFrameEventObserver);
|
||||
}
|
||||
|
||||
void Screen::forceDisplay()
|
||||
@@ -878,6 +887,9 @@ int32_t Screen::runOnce()
|
||||
handlePrint(cmd.print_text);
|
||||
free(cmd.print_text);
|
||||
break;
|
||||
case Cmd::START_SHUTDOWN_SCREEN:
|
||||
handleShutdownScreen();
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("BUG: invalid cmd\n");
|
||||
}
|
||||
@@ -930,20 +942,20 @@ int32_t Screen::runOnce()
|
||||
|
||||
void Screen::drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
Screen *screen = reinterpret_cast<Screen *>(state->userData);
|
||||
screen->debugInfo.drawFrame(display, state, x, y);
|
||||
Screen *screen2 = reinterpret_cast<Screen *>(state->userData);
|
||||
screen2->debugInfo.drawFrame(display, state, x, y);
|
||||
}
|
||||
|
||||
void Screen::drawDebugInfoSettingsTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
Screen *screen = reinterpret_cast<Screen *>(state->userData);
|
||||
screen->debugInfo.drawFrameSettings(display, state, x, y);
|
||||
Screen *screen2 = reinterpret_cast<Screen *>(state->userData);
|
||||
screen2->debugInfo.drawFrameSettings(display, state, x, y);
|
||||
}
|
||||
|
||||
void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
Screen *screen = reinterpret_cast<Screen *>(state->userData);
|
||||
screen->debugInfo.drawFrameWiFi(display, state, x, y);
|
||||
Screen *screen2 = reinterpret_cast<Screen *>(state->userData);
|
||||
screen2->debugInfo.drawFrameWiFi(display, state, x, y);
|
||||
}
|
||||
|
||||
/* show a message that the SSL cert is being built
|
||||
@@ -964,9 +976,9 @@ void Screen::setFrames()
|
||||
DEBUG_MSG("showing standard frames\n");
|
||||
showingNormalScreen = true;
|
||||
|
||||
pluginFrames = MeshPlugin::GetMeshPluginsWithUIFrames();
|
||||
DEBUG_MSG("Showing %d plugin frames\n", pluginFrames.size());
|
||||
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + pluginFrames.size();
|
||||
moduleFrames = MeshPlugin::GetMeshModulesWithUIFrames();
|
||||
DEBUG_MSG("Showing %d module frames\n", moduleFrames.size());
|
||||
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
|
||||
DEBUG_MSG("Total frame count: %d\n", totalFrameCount);
|
||||
|
||||
// We don't show the node info our our node (if we have it yet - we should)
|
||||
@@ -976,23 +988,23 @@ void Screen::setFrames()
|
||||
|
||||
size_t numframes = 0;
|
||||
|
||||
// put all of the plugin frames first.
|
||||
// put all of the module frames first.
|
||||
// this is a little bit of a dirty hack; since we're going to call
|
||||
// the same drawPluginFrame handler here for all of these plugin frames
|
||||
// the same drawModuleFrame handler here for all of these module frames
|
||||
// and then we'll just assume that the state->currentFrame value
|
||||
// is the same offset into the pluginFrames vector
|
||||
// so that we can invoke the plugin's callback
|
||||
for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) {
|
||||
normalFrames[numframes++] = drawPluginFrame;
|
||||
// is the same offset into the moduleFrames vector
|
||||
// so that we can invoke the module's callback
|
||||
for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) {
|
||||
normalFrames[numframes++] = drawModuleFrame;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
|
||||
DEBUG_MSG("Added modules. numframes: %d\n", numframes);
|
||||
|
||||
// If we have a critical fault, show it first
|
||||
if (myNodeInfo.error_code)
|
||||
normalFrames[numframes++] = drawCriticalFaultFrame;
|
||||
|
||||
// If we have a text message - show it next, unless it's a phone message and we aren't using any special plugins
|
||||
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
|
||||
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
|
||||
normalFrames[numframes++] = drawTextMessageFrame;
|
||||
}
|
||||
@@ -1037,13 +1049,25 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
||||
|
||||
static FrameCallback btFrames[] = {drawFrameBluetooth};
|
||||
|
||||
snprintf(btPIN, sizeof(btPIN), "%06lu", pin);
|
||||
snprintf(btPIN, sizeof(btPIN), "%06u", pin);
|
||||
|
||||
ui.disableAllIndicators();
|
||||
ui.setFrames(btFrames, 1);
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
void Screen::handleShutdownScreen()
|
||||
{
|
||||
DEBUG_MSG("showing shutdown screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback shutdownFrames[] = {drawFrameShutdown};
|
||||
|
||||
ui.disableAllIndicators();
|
||||
ui.setFrames(shutdownFrames, 1);
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
void Screen::handleStartFirmwareUpdateScreen()
|
||||
{
|
||||
DEBUG_MSG("showing firmware screen\n");
|
||||
@@ -1457,4 +1481,23 @@ int Screen::handleTextMessage(const MeshPacket *packet)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
{
|
||||
if (showingNormalScreen) {
|
||||
if (event->frameChanged)
|
||||
{
|
||||
setFrames(); // Regen the list of screens (will show new text message)
|
||||
}
|
||||
else if (event->needRedraw)
|
||||
{
|
||||
setFastFramerate();
|
||||
// TODO: We might also want switch to corresponding frame,
|
||||
// but we don't know the exact frame number.
|
||||
//ui.switchToFrame(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -40,6 +40,7 @@ class Screen
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "power.h"
|
||||
#include <string>
|
||||
#include "mesh/MeshPlugin.h"
|
||||
|
||||
// 0 to 255, though particular variants might define different defaults
|
||||
#ifndef BRIGHTNESS_DEFAULT
|
||||
@@ -90,9 +91,11 @@ class Screen : public concurrency::OSThread
|
||||
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||
CallbackObserver<Screen, const MeshPacket *> textMessageObserver =
|
||||
CallbackObserver<Screen, const MeshPacket *>(this, &Screen::handleTextMessage);
|
||||
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
||||
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
|
||||
|
||||
public:
|
||||
Screen(uint8_t address, int sda = -1, int scl = -1);
|
||||
explicit Screen(uint8_t address, int sda = -1, int scl = -1);
|
||||
|
||||
Screen(const Screen &) = delete;
|
||||
Screen &operator=(const Screen &) = delete;
|
||||
@@ -148,6 +151,12 @@ class Screen : public concurrency::OSThread
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
void startShutdownScreen()
|
||||
{
|
||||
ScreenCmd cmd;
|
||||
cmd.cmd = Cmd::START_SHUTDOWN_SCREEN;
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
/// Stops showing the bluetooth PIN screen.
|
||||
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
|
||||
@@ -218,6 +227,7 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||
int handleTextMessage(const MeshPacket *arg);
|
||||
int handleUIFrameEvent(const UIFrameEvent *arg);
|
||||
|
||||
/// Used to force (super slow) eink displays to draw critical frames
|
||||
void forceDisplay();
|
||||
@@ -258,7 +268,7 @@ class Screen : public concurrency::OSThread
|
||||
void handleStartBluetoothPinScreen(uint32_t pin);
|
||||
void handlePrint(const char *text);
|
||||
void handleStartFirmwareUpdateScreen();
|
||||
|
||||
void handleShutdownScreen();
|
||||
/// Rebuilds our list of frames (screens) to default ones.
|
||||
void setFrames();
|
||||
|
||||
@@ -303,4 +313,4 @@ class Screen : public concurrency::OSThread
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -21,15 +21,15 @@ class TFTDisplay : public OLEDDisplay
|
||||
TFTDisplay(uint8_t address, int sda, int scl);
|
||||
|
||||
// Write the buffer to the display memory
|
||||
virtual void display(void);
|
||||
virtual void display(void) override;
|
||||
|
||||
protected:
|
||||
// the header size of the buffer used, e.g. for the SPI command header
|
||||
virtual int getBufferOffset(void) { return 0; }
|
||||
virtual int getBufferOffset(void) override { return 0; }
|
||||
|
||||
// Send a command to the display (low level function)
|
||||
virtual void sendCommand(uint8_t com);
|
||||
virtual void sendCommand(uint8_t com) override;
|
||||
|
||||
// Connect to the display
|
||||
virtual bool connect();
|
||||
virtual bool connect() override;
|
||||
};
|
||||
|
||||
@@ -1,425 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
const uint8_t Custom_ArialMT_Plain_10[] PROGMEM = {
|
||||
0x0A, // Width: 10
|
||||
0x0A, // Height: 10
|
||||
0x20, // First Char: 32
|
||||
0xE0, // Numbers of Chars: 224
|
||||
|
||||
// Jump Table:
|
||||
0xFF, 0xFF, 0x00, 0x03, // 32:65535
|
||||
0x00, 0x00, 0x04, 0x03, // 33:0
|
||||
0x00, 0x04, 0x05, 0x04, // 34:4
|
||||
0x00, 0x09, 0x09, 0x06, // 35:9
|
||||
0x00, 0x12, 0x0A, 0x06, // 36:18
|
||||
0x00, 0x1C, 0x10, 0x09, // 37:28
|
||||
0x00, 0x2C, 0x0E, 0x07, // 38:44
|
||||
0x00, 0x3A, 0x01, 0x02, // 39:58
|
||||
0x00, 0x3B, 0x06, 0x03, // 40:59
|
||||
0x00, 0x41, 0x06, 0x03, // 41:65
|
||||
0x00, 0x47, 0x05, 0x04, // 42:71
|
||||
0x00, 0x4C, 0x09, 0x06, // 43:76
|
||||
0x00, 0x55, 0x04, 0x03, // 44:85
|
||||
0x00, 0x59, 0x03, 0x03, // 45:89
|
||||
0x00, 0x5C, 0x04, 0x03, // 46:92
|
||||
0x00, 0x60, 0x05, 0x03, // 47:96
|
||||
0x00, 0x65, 0x0A, 0x06, // 48:101
|
||||
0x00, 0x6F, 0x08, 0x06, // 49:111
|
||||
0x00, 0x77, 0x0A, 0x06, // 50:119
|
||||
0x00, 0x81, 0x0A, 0x06, // 51:129
|
||||
0x00, 0x8B, 0x0B, 0x06, // 52:139
|
||||
0x00, 0x96, 0x0A, 0x06, // 53:150
|
||||
0x00, 0xA0, 0x0A, 0x06, // 54:160
|
||||
0x00, 0xAA, 0x09, 0x06, // 55:170
|
||||
0x00, 0xB3, 0x0A, 0x06, // 56:179
|
||||
0x00, 0xBD, 0x0A, 0x06, // 57:189
|
||||
0x00, 0xC7, 0x04, 0x03, // 58:199
|
||||
0x00, 0xCB, 0x04, 0x03, // 59:203
|
||||
0x00, 0xCF, 0x0A, 0x06, // 60:207
|
||||
0x00, 0xD9, 0x09, 0x06, // 61:217
|
||||
0x00, 0xE2, 0x09, 0x06, // 62:226
|
||||
0x00, 0xEB, 0x0B, 0x06, // 63:235
|
||||
0x00, 0xF6, 0x14, 0x0A, // 64:246
|
||||
0x01, 0x0A, 0x0E, 0x07, // 65:266
|
||||
0x01, 0x18, 0x0C, 0x07, // 66:280
|
||||
0x01, 0x24, 0x0C, 0x07, // 67:292
|
||||
0x01, 0x30, 0x0B, 0x07, // 68:304
|
||||
0x01, 0x3B, 0x0C, 0x07, // 69:315
|
||||
0x01, 0x47, 0x09, 0x06, // 70:327
|
||||
0x01, 0x50, 0x0D, 0x08, // 71:336
|
||||
0x01, 0x5D, 0x0C, 0x07, // 72:349
|
||||
0x01, 0x69, 0x04, 0x03, // 73:361
|
||||
0x01, 0x6D, 0x08, 0x05, // 74:365
|
||||
0x01, 0x75, 0x0E, 0x07, // 75:373
|
||||
0x01, 0x83, 0x0C, 0x06, // 76:387
|
||||
0x01, 0x8F, 0x10, 0x08, // 77:399
|
||||
0x01, 0x9F, 0x0C, 0x07, // 78:415
|
||||
0x01, 0xAB, 0x0E, 0x08, // 79:427
|
||||
0x01, 0xB9, 0x0B, 0x07, // 80:441
|
||||
0x01, 0xC4, 0x0E, 0x08, // 81:452
|
||||
0x01, 0xD2, 0x0C, 0x07, // 82:466
|
||||
0x01, 0xDE, 0x0C, 0x07, // 83:478
|
||||
0x01, 0xEA, 0x0B, 0x06, // 84:490
|
||||
0x01, 0xF5, 0x0C, 0x07, // 85:501
|
||||
0x02, 0x01, 0x0D, 0x07, // 86:513
|
||||
0x02, 0x0E, 0x11, 0x09, // 87:526
|
||||
0x02, 0x1F, 0x0E, 0x07, // 88:543
|
||||
0x02, 0x2D, 0x0D, 0x07, // 89:557
|
||||
0x02, 0x3A, 0x0C, 0x06, // 90:570
|
||||
0x02, 0x46, 0x06, 0x03, // 91:582
|
||||
0x02, 0x4C, 0x06, 0x03, // 92:588
|
||||
0x02, 0x52, 0x04, 0x03, // 93:594
|
||||
0x02, 0x56, 0x09, 0x05, // 94:598
|
||||
0x02, 0x5F, 0x0C, 0x06, // 95:607
|
||||
0x02, 0x6B, 0x03, 0x03, // 96:619
|
||||
0x02, 0x6E, 0x0A, 0x06, // 97:622
|
||||
0x02, 0x78, 0x0A, 0x06, // 98:632
|
||||
0x02, 0x82, 0x0A, 0x05, // 99:642
|
||||
0x02, 0x8C, 0x0A, 0x06, // 100:652
|
||||
0x02, 0x96, 0x0A, 0x06, // 101:662
|
||||
0x02, 0xA0, 0x05, 0x03, // 102:672
|
||||
0x02, 0xA5, 0x0A, 0x06, // 103:677
|
||||
0x02, 0xAF, 0x0A, 0x06, // 104:687
|
||||
0x02, 0xB9, 0x04, 0x02, // 105:697
|
||||
0x02, 0xBD, 0x04, 0x02, // 106:701
|
||||
0x02, 0xC1, 0x08, 0x05, // 107:705
|
||||
0x02, 0xC9, 0x04, 0x02, // 108:713
|
||||
0x02, 0xCD, 0x10, 0x08, // 109:717
|
||||
0x02, 0xDD, 0x0A, 0x06, // 110:733
|
||||
0x02, 0xE7, 0x0A, 0x06, // 111:743
|
||||
0x02, 0xF1, 0x0A, 0x06, // 112:753
|
||||
0x02, 0xFB, 0x0A, 0x06, // 113:763
|
||||
0x03, 0x05, 0x05, 0x03, // 114:773
|
||||
0x03, 0x0A, 0x08, 0x05, // 115:778
|
||||
0x03, 0x12, 0x06, 0x03, // 116:786
|
||||
0x03, 0x18, 0x0A, 0x06, // 117:792
|
||||
0x03, 0x22, 0x09, 0x05, // 118:802
|
||||
0x03, 0x2B, 0x0E, 0x07, // 119:811
|
||||
0x03, 0x39, 0x0A, 0x05, // 120:825
|
||||
0x03, 0x43, 0x09, 0x05, // 121:835
|
||||
0x03, 0x4C, 0x0A, 0x05, // 122:844
|
||||
0x03, 0x56, 0x06, 0x03, // 123:854
|
||||
0x03, 0x5C, 0x04, 0x03, // 124:860
|
||||
0x03, 0x60, 0x05, 0x03, // 125:864
|
||||
0x03, 0x65, 0x09, 0x06, // 126:869
|
||||
0xFF, 0xFF, 0x00, 0x00, // 127:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 128:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 129:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 130:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 131:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 132:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 133:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 134:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 135:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 136:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 137:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 138:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 139:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 140:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 141:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 142:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 143:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 144:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 145:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 146:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 147:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 148:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 149:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 150:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 151:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 152:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 153:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 154:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 155:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 156:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 157:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 158:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 159:65535
|
||||
0xFF, 0xFF, 0x00, 0x03, // 160:65535
|
||||
0x03, 0x6E, 0x04, 0x03, // 161:878
|
||||
0x03, 0x72, 0x0A, 0x06, // 162:882
|
||||
0x03, 0x7C, 0x0C, 0x06, // 163:892
|
||||
0x03, 0x88, 0x0A, 0x06, // 164:904
|
||||
0x03, 0x92, 0x0A, 0x06, // 165:914
|
||||
0x03, 0x9C, 0x04, 0x03, // 166:924
|
||||
0x03, 0xA0, 0x0A, 0x06, // 167:928
|
||||
0x03, 0xAA, 0x05, 0x03, // 168:938
|
||||
0x03, 0xAF, 0x0D, 0x07, // 169:943
|
||||
0x03, 0xBC, 0x07, 0x04, // 170:956
|
||||
0x03, 0xC3, 0x0A, 0x06, // 171:963
|
||||
0x03, 0xCD, 0x09, 0x06, // 172:973
|
||||
0x03, 0xD6, 0x03, 0x03, // 173:982
|
||||
0x03, 0xD9, 0x0D, 0x07, // 174:985
|
||||
0x03, 0xE6, 0x0B, 0x06, // 175:998
|
||||
0x03, 0xF1, 0x07, 0x04, // 176:1009
|
||||
0x03, 0xF8, 0x0A, 0x05, // 177:1016
|
||||
0x04, 0x02, 0x05, 0x03, // 178:1026
|
||||
0x04, 0x07, 0x05, 0x03, // 179:1031
|
||||
0x04, 0x0C, 0x05, 0x03, // 180:1036
|
||||
0x04, 0x11, 0x0A, 0x06, // 181:1041
|
||||
0x04, 0x1B, 0x09, 0x05, // 182:1051
|
||||
0x04, 0x24, 0x03, 0x03, // 183:1060
|
||||
0x04, 0x27, 0x06, 0x03, // 184:1063
|
||||
0x04, 0x2D, 0x05, 0x03, // 185:1069
|
||||
0x04, 0x32, 0x07, 0x04, // 186:1074
|
||||
0x04, 0x39, 0x0A, 0x06, // 187:1081
|
||||
0x04, 0x43, 0x10, 0x08, // 188:1091
|
||||
0x04, 0x53, 0x10, 0x08, // 189:1107
|
||||
0x04, 0x63, 0x10, 0x08, // 190:1123
|
||||
0x04, 0x73, 0x0A, 0x06, // 191:1139
|
||||
0x04, 0x7D, 0x0E, 0x07, // 192:1149
|
||||
0x04, 0x8B, 0x0E, 0x07, // 193:1163
|
||||
0x04, 0x99, 0x0E, 0x07, // 194:1177
|
||||
0x04, 0xA7, 0x0E, 0x07, // 195:1191
|
||||
0x04, 0xB5, 0x0E, 0x07, // 196:1205
|
||||
0x04, 0xC3, 0x0E, 0x07, // 197:1219
|
||||
0x04, 0xD1, 0x12, 0x0A, // 198:1233
|
||||
0x04, 0xE3, 0x0C, 0x07, // 199:1251
|
||||
0x04, 0xEF, 0x0C, 0x07, // 200:1263
|
||||
0x04, 0xFB, 0x0C, 0x07, // 201:1275
|
||||
0x05, 0x07, 0x0C, 0x07, // 202:1287
|
||||
0x05, 0x13, 0x0C, 0x07, // 203:1299
|
||||
0x05, 0x1F, 0x05, 0x03, // 204:1311
|
||||
0x05, 0x24, 0x04, 0x03, // 205:1316
|
||||
0x05, 0x28, 0x04, 0x03, // 206:1320
|
||||
0x05, 0x2C, 0x05, 0x03, // 207:1324
|
||||
0x05, 0x31, 0x0B, 0x07, // 208:1329
|
||||
0x05, 0x3C, 0x0C, 0x07, // 209:1340
|
||||
0x05, 0x48, 0x0E, 0x08, // 210:1352
|
||||
0x05, 0x56, 0x0E, 0x08, // 211:1366
|
||||
0x05, 0x64, 0x0E, 0x08, // 212:1380
|
||||
0x05, 0x72, 0x0E, 0x08, // 213:1394
|
||||
0x05, 0x80, 0x0E, 0x08, // 214:1408
|
||||
0x05, 0x8E, 0x0A, 0x06, // 215:1422
|
||||
0x05, 0x98, 0x0D, 0x08, // 216:1432
|
||||
0x05, 0xA5, 0x0C, 0x07, // 217:1445
|
||||
0x05, 0xB1, 0x0C, 0x07, // 218:1457
|
||||
0x05, 0xBD, 0x0C, 0x07, // 219:1469
|
||||
0x05, 0xC9, 0x0C, 0x07, // 220:1481
|
||||
0x05, 0xD5, 0x0D, 0x07, // 221:1493
|
||||
0x05, 0xE2, 0x0B, 0x07, // 222:1506
|
||||
0x05, 0xED, 0x0C, 0x06, // 223:1517
|
||||
0x05, 0xF9, 0x0A, 0x06, // 224:1529
|
||||
0x06, 0x03, 0x0A, 0x06, // 225:1539
|
||||
0x06, 0x0D, 0x0A, 0x06, // 226:1549
|
||||
0x06, 0x17, 0x0A, 0x06, // 227:1559
|
||||
0x06, 0x21, 0x0A, 0x06, // 228:1569
|
||||
0x06, 0x2B, 0x0A, 0x06, // 229:1579
|
||||
0x06, 0x35, 0x10, 0x09, // 230:1589
|
||||
0x06, 0x45, 0x0A, 0x05, // 231:1605
|
||||
0x06, 0x4F, 0x0A, 0x06, // 232:1615
|
||||
0x06, 0x59, 0x0A, 0x06, // 233:1625
|
||||
0x06, 0x63, 0x0A, 0x06, // 234:1635
|
||||
0x06, 0x6D, 0x0A, 0x06, // 235:1645
|
||||
0x06, 0x77, 0x05, 0x03, // 236:1655
|
||||
0x06, 0x7C, 0x04, 0x03, // 237:1660
|
||||
0x06, 0x80, 0x05, 0x03, // 238:1664
|
||||
0x06, 0x85, 0x05, 0x03, // 239:1669
|
||||
0x06, 0x8A, 0x0A, 0x06, // 240:1674
|
||||
0x06, 0x94, 0x0A, 0x06, // 241:1684
|
||||
0x06, 0x9E, 0x0A, 0x06, // 242:1694
|
||||
0x06, 0xA8, 0x0A, 0x06, // 243:1704
|
||||
0x06, 0xB2, 0x0A, 0x06, // 244:1714
|
||||
0x06, 0xBC, 0x0A, 0x06, // 245:1724
|
||||
0x06, 0xC6, 0x0A, 0x06, // 246:1734
|
||||
0x06, 0xD0, 0x09, 0x05, // 247:1744
|
||||
0x06, 0xD9, 0x0A, 0x06, // 248:1753
|
||||
0x06, 0xE3, 0x0A, 0x06, // 249:1763
|
||||
0x06, 0xED, 0x0A, 0x06, // 250:1773
|
||||
0x06, 0xF7, 0x0A, 0x06, // 251:1783
|
||||
0x07, 0x01, 0x0A, 0x06, // 252:1793
|
||||
0x07, 0x0B, 0x09, 0x05, // 253:1803
|
||||
0x07, 0x14, 0x0A, 0x06, // 254:1812
|
||||
0x07, 0x1E, 0x09, 0x05, // 255:1822
|
||||
|
||||
// Font Data:
|
||||
0x00, 0x00, 0xF8, 0x02, // 33
|
||||
0x38, 0x00, 0x00, 0x00, 0x38, // 34
|
||||
0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35
|
||||
0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36
|
||||
0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37
|
||||
0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38
|
||||
0x38, // 39
|
||||
0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40
|
||||
0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41
|
||||
0x28, 0x00, 0x18, 0x00, 0x28, // 42
|
||||
0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43
|
||||
0x00, 0x00, 0x00, 0x06, // 44
|
||||
0x80, 0x00, 0x80, // 45
|
||||
0x00, 0x00, 0x00, 0x02, // 46
|
||||
0x00, 0x03, 0xE0, 0x00, 0x18, // 47
|
||||
0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48
|
||||
0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49
|
||||
0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50
|
||||
0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51
|
||||
0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52
|
||||
0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53
|
||||
0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54
|
||||
0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55
|
||||
0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56
|
||||
0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57
|
||||
0x00, 0x00, 0x20, 0x02, // 58
|
||||
0x00, 0x00, 0x20, 0x06, // 59
|
||||
0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60
|
||||
0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61
|
||||
0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62
|
||||
0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63
|
||||
0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0, 0x04, // 64
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67
|
||||
0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70
|
||||
0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71
|
||||
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72
|
||||
0x00, 0x00, 0xF8, 0x03, // 73
|
||||
0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74
|
||||
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75
|
||||
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76
|
||||
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77
|
||||
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82
|
||||
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83
|
||||
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84
|
||||
0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85
|
||||
0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86
|
||||
0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87
|
||||
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88
|
||||
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89
|
||||
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90
|
||||
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91
|
||||
0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92
|
||||
0x08, 0x08, 0xF8, 0x0F, // 93
|
||||
0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94
|
||||
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95
|
||||
0x08, 0x00, 0x10, // 96
|
||||
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97
|
||||
0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101
|
||||
0x20, 0x00, 0xF0, 0x03, 0x28, // 102
|
||||
0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103
|
||||
0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104
|
||||
0x00, 0x00, 0xE8, 0x03, // 105
|
||||
0x00, 0x08, 0xE8, 0x07, // 106
|
||||
0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107
|
||||
0x00, 0x00, 0xF8, 0x03, // 108
|
||||
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109
|
||||
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111
|
||||
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113
|
||||
0x00, 0x00, 0xE0, 0x03, 0x20, // 114
|
||||
0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115
|
||||
0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116
|
||||
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117
|
||||
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118
|
||||
0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119
|
||||
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120
|
||||
0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121
|
||||
0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122
|
||||
0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123
|
||||
0x00, 0x00, 0xF8, 0x0F, // 124
|
||||
0x08, 0x08, 0x78, 0x0F, 0x80, // 125
|
||||
0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126
|
||||
0x00, 0x00, 0xA0, 0x0F, // 161
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x0F, 0x78, 0x02, 0x40, 0x01, // 162
|
||||
0x40, 0x02, 0x70, 0x03, 0xC8, 0x02, 0x48, 0x02, 0x08, 0x02, 0x10, 0x02, // 163
|
||||
0x00, 0x00, 0xE0, 0x01, 0x20, 0x01, 0x20, 0x01, 0xE0, 0x01, // 164
|
||||
0x48, 0x01, 0x70, 0x01, 0xC0, 0x03, 0x70, 0x01, 0x48, 0x01, // 165
|
||||
0x00, 0x00, 0x38, 0x0F, // 166
|
||||
0xD0, 0x04, 0x28, 0x09, 0x48, 0x09, 0x48, 0x0A, 0x90, 0x05, // 167
|
||||
0x08, 0x00, 0x00, 0x00, 0x08, // 168
|
||||
0xE0, 0x00, 0x10, 0x01, 0x48, 0x02, 0xA8, 0x02, 0xA8, 0x02, 0x10, 0x01, 0xE0, // 169
|
||||
0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x78, // 170
|
||||
0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, // 171
|
||||
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, // 172
|
||||
0x80, 0x00, 0x80, // 173
|
||||
0xE0, 0x00, 0x10, 0x01, 0xE8, 0x02, 0x68, 0x02, 0xC8, 0x02, 0x10, 0x01, 0xE0, // 174
|
||||
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 175
|
||||
0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176
|
||||
0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177
|
||||
0x48, 0x00, 0x68, 0x00, 0x58, // 178
|
||||
0x48, 0x00, 0x58, 0x00, 0x68, // 179
|
||||
0x00, 0x00, 0x10, 0x00, 0x08, // 180
|
||||
0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 181
|
||||
0x70, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0xF8, 0x0F, 0x08, // 182
|
||||
0x00, 0x00, 0x40, // 183
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x18, // 184
|
||||
0x00, 0x00, 0x10, 0x00, 0x78, // 185
|
||||
0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 186
|
||||
0x00, 0x00, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, // 187
|
||||
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188
|
||||
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189
|
||||
0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190
|
||||
0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0xA0, 0x09, 0x00, 0x04, // 191
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 192
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 193
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 194
|
||||
0x00, 0x02, 0xC2, 0x01, 0xB1, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 195
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x88, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 196
|
||||
0x00, 0x02, 0xC0, 0x01, 0xBE, 0x00, 0x8A, 0x00, 0xBE, 0x00, 0xC0, 0x01, 0x00, 0x02, // 197
|
||||
0x00, 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x98, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 198
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x16, 0x08, 0x1A, 0x10, 0x01, // 199
|
||||
0x00, 0x00, 0xF8, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 200
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x4A, 0x02, 0x49, 0x02, 0x48, 0x02, // 201
|
||||
0x00, 0x00, 0xFA, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 202
|
||||
0x00, 0x00, 0xF8, 0x03, 0x4A, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x48, 0x02, // 203
|
||||
0x00, 0x00, 0xF9, 0x03, 0x02, // 204
|
||||
0x02, 0x00, 0xF9, 0x03, // 205
|
||||
0x01, 0x00, 0xFA, 0x03, // 206
|
||||
0x02, 0x00, 0xF8, 0x03, 0x02, // 207
|
||||
0x40, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x10, 0x01, 0xE0, // 208
|
||||
0x00, 0x00, 0xFA, 0x03, 0x31, 0x00, 0x42, 0x00, 0x81, 0x01, 0xF8, 0x03, // 209
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 210
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x08, 0x02, 0xF0, 0x01, // 211
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0xF0, 0x01, // 212
|
||||
0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x09, 0x02, 0xF0, 0x01, // 213
|
||||
0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 214
|
||||
0x10, 0x01, 0xA0, 0x00, 0xE0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 215
|
||||
0x00, 0x00, 0xF0, 0x02, 0x08, 0x03, 0xC8, 0x02, 0x28, 0x02, 0x18, 0x03, 0xE8, // 216
|
||||
0x00, 0x00, 0xF8, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02, 0xF8, 0x01, // 217
|
||||
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, 0xF8, 0x01, // 218
|
||||
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0xF8, 0x01, // 219
|
||||
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0xF8, 0x01, // 220
|
||||
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC2, 0x03, 0x21, 0x00, 0x10, 0x00, 0x08, // 221
|
||||
0x00, 0x00, 0xF8, 0x03, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xE0, // 222
|
||||
0x00, 0x00, 0xF0, 0x03, 0x08, 0x01, 0x48, 0x02, 0xB0, 0x02, 0x80, 0x01, // 223
|
||||
0x00, 0x00, 0x00, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE0, 0x03, // 224
|
||||
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE0, 0x03, // 225
|
||||
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE8, 0x03, // 226
|
||||
0x00, 0x00, 0x08, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE4, 0x03, // 227
|
||||
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA0, 0x02, 0xE8, 0x03, // 228
|
||||
0x00, 0x00, 0x00, 0x03, 0xAE, 0x02, 0xAA, 0x02, 0xEE, 0x03, // 229
|
||||
0x00, 0x00, 0x40, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 230
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x16, 0x20, 0x1A, 0x40, 0x01, // 231
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA4, 0x02, 0xA8, 0x02, 0xC0, 0x02, // 232
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC0, 0x02, // 233
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC8, 0x02, // 234
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA0, 0x02, 0xC8, 0x02, // 235
|
||||
0x00, 0x00, 0xE4, 0x03, 0x08, // 236
|
||||
0x08, 0x00, 0xE4, 0x03, // 237
|
||||
0x08, 0x00, 0xE4, 0x03, 0x08, // 238
|
||||
0x08, 0x00, 0xE0, 0x03, 0x08, // 239
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x38, 0x02, 0xE0, 0x01, // 240
|
||||
0x00, 0x00, 0xE8, 0x03, 0x24, 0x00, 0x28, 0x00, 0xC4, 0x03, // 241
|
||||
0x00, 0x00, 0xC0, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC0, 0x01, // 242
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC0, 0x01, // 243
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC8, 0x01, // 244
|
||||
0x00, 0x00, 0xC8, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC4, 0x01, // 245
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x20, 0x02, 0xC8, 0x01, // 246
|
||||
0x40, 0x00, 0x40, 0x00, 0x50, 0x01, 0x40, 0x00, 0x40, // 247
|
||||
0x00, 0x00, 0xC0, 0x02, 0xA0, 0x03, 0x60, 0x02, 0xA0, 0x01, // 248
|
||||
0x00, 0x00, 0xE0, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 249
|
||||
0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x04, 0x02, 0xE0, 0x03, // 250
|
||||
0x00, 0x00, 0xE8, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 251
|
||||
0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x00, 0x02, 0xE8, 0x03, // 252
|
||||
0x20, 0x00, 0xC0, 0x09, 0x08, 0x06, 0xC4, 0x01, 0x20, // 253
|
||||
0x00, 0x00, 0xF8, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 254
|
||||
0x20, 0x00, 0xC8, 0x09, 0x00, 0x06, 0xC8, 0x01, 0x20 // 255
|
||||
};
|
||||
18
src/input/InputBroker.cpp
Normal file
18
src/input/InputBroker.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "InputBroker.h"
|
||||
|
||||
InputBroker *inputBroker;
|
||||
|
||||
InputBroker::InputBroker()
|
||||
{
|
||||
};
|
||||
|
||||
void InputBroker::registerSource(Observable<const InputEvent *> *source)
|
||||
{
|
||||
this->inputEventObserver.observe(source);
|
||||
}
|
||||
|
||||
int InputBroker::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
this->notifyObservers(event);
|
||||
return 0;
|
||||
}
|
||||
22
src/input/InputBroker.h
Normal file
22
src/input/InputBroker.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "Observer.h"
|
||||
|
||||
typedef struct _InputEvent {
|
||||
const char* source;
|
||||
char inputEvent;
|
||||
} InputEvent;
|
||||
class InputBroker :
|
||||
public Observable<const InputEvent *>
|
||||
{
|
||||
CallbackObserver<InputBroker, const InputEvent *> inputEventObserver =
|
||||
CallbackObserver<InputBroker, const InputEvent *>(this, &InputBroker::handleInputEvent);
|
||||
|
||||
public:
|
||||
InputBroker();
|
||||
void registerSource(Observable<const InputEvent *> *source);
|
||||
|
||||
protected:
|
||||
int handleInputEvent(const InputEvent *event);
|
||||
};
|
||||
|
||||
extern InputBroker *inputBroker;
|
||||
148
src/input/RotaryEncoderInterruptBase.cpp
Normal file
148
src/input/RotaryEncoderInterruptBase.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "configuration.h"
|
||||
#include "RotaryEncoderInterruptBase.h"
|
||||
|
||||
RotaryEncoderInterruptBase::RotaryEncoderInterruptBase(
|
||||
const char *name) :
|
||||
concurrency::OSThread(name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptBase::init(
|
||||
uint8_t pinA, uint8_t pinB, uint8_t pinPress,
|
||||
char eventCw, char eventCcw, char eventPressed,
|
||||
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress) :
|
||||
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)())
|
||||
{
|
||||
this->_pinA = pinA;
|
||||
this->_pinB = pinB;
|
||||
this->_eventCw = eventCw;
|
||||
this->_eventCcw = eventCcw;
|
||||
this->_eventPressed = eventPressed;
|
||||
|
||||
pinMode(pinPress, INPUT_PULLUP);
|
||||
pinMode(this->_pinA, INPUT_PULLUP);
|
||||
pinMode(this->_pinB, INPUT_PULLUP);
|
||||
|
||||
// attachInterrupt(pinPress, onIntPress, RISING);
|
||||
attachInterrupt(pinPress, onIntPress, RISING);
|
||||
attachInterrupt(this->_pinA, onIntA, CHANGE);
|
||||
attachInterrupt(this->_pinB, onIntB, CHANGE);
|
||||
|
||||
this->rotaryLevelA = digitalRead(this->_pinA);
|
||||
this->rotaryLevelB = digitalRead(this->_pinB);
|
||||
DEBUG_MSG("Rotary initialized (%d, %d, %d)\n",
|
||||
this->_pinA, this->_pinB, pinPress);
|
||||
}
|
||||
|
||||
|
||||
int32_t RotaryEncoderInterruptBase::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = InputEventChar_KEY_NONE;
|
||||
e.source = this->_originName;
|
||||
|
||||
if (this->action == ROTARY_ACTION_PRESSED)
|
||||
{
|
||||
DEBUG_MSG("Rotary event Press\n");
|
||||
e.inputEvent = this->_eventPressed;
|
||||
}
|
||||
else if (this->action == ROTARY_ACTION_CW)
|
||||
{
|
||||
DEBUG_MSG("Rotary event CW\n");
|
||||
e.inputEvent = this->_eventCw;
|
||||
}
|
||||
else if (this->action == ROTARY_ACTION_CCW)
|
||||
{
|
||||
DEBUG_MSG("Rotary event CW\n");
|
||||
e.inputEvent = this->_eventCcw;
|
||||
}
|
||||
|
||||
if (e.inputEvent != InputEventChar_KEY_NONE)
|
||||
{
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
this->action = ROTARY_ACTION_NONE;
|
||||
|
||||
return 30000; // TODO: technically this can be MAX_INT
|
||||
}
|
||||
|
||||
|
||||
void RotaryEncoderInterruptBase::intPressHandler()
|
||||
{
|
||||
this->action = ROTARY_ACTION_PRESSED;
|
||||
setIntervalFromNow(20); // TODO: this modifies a non-volatile variable!
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptBase::intAHandler()
|
||||
{
|
||||
// CW rotation (at least on most common rotary encoders)
|
||||
int currentLevelA = digitalRead(this->_pinA);
|
||||
if (this->rotaryLevelA == currentLevelA)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->rotaryLevelA = currentLevelA;
|
||||
intHandler(
|
||||
currentLevelA == HIGH,
|
||||
this->rotaryLevelB,
|
||||
ROTARY_ACTION_CCW,
|
||||
this->rotaryStateCCW);
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptBase::intBHandler()
|
||||
{
|
||||
// CW rotation (at least on most common rotary encoders)
|
||||
int currentLevelB = digitalRead(this->_pinB);
|
||||
if (this->rotaryLevelB == currentLevelB)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->rotaryLevelB = currentLevelB;
|
||||
this->rotaryStateCW = intHandler(
|
||||
currentLevelB == HIGH,
|
||||
this->rotaryLevelA,
|
||||
ROTARY_ACTION_CW,
|
||||
this->rotaryStateCW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rotary action implementation.
|
||||
* We assume, the following pin setup:
|
||||
* A --||
|
||||
* GND --||]========
|
||||
* B --||
|
||||
*
|
||||
* @return The new state for rotary pin.
|
||||
*/
|
||||
RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler(
|
||||
bool actualPinRaising,
|
||||
int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state)
|
||||
{
|
||||
RotaryEncoderInterruptBaseStateType newState =
|
||||
state;
|
||||
if (actualPinRaising && (otherPinLevel == LOW))
|
||||
{
|
||||
if (state == ROTARY_EVENT_CLEARED)
|
||||
{
|
||||
newState = ROTARY_EVENT_OCCURRED;
|
||||
if ((this->action != ROTARY_ACTION_PRESSED)
|
||||
&& (this->action != action))
|
||||
{
|
||||
this->action = action;
|
||||
DEBUG_MSG("Rotary action\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!actualPinRaising && (otherPinLevel == HIGH))
|
||||
{
|
||||
// Logic to prevent bouncing.
|
||||
newState = ROTARY_EVENT_CLEARED;
|
||||
}
|
||||
setIntervalFromNow(50); // TODO: this modifies a non-volatile variable!
|
||||
|
||||
return newState;
|
||||
}
|
||||
57
src/input/RotaryEncoderInterruptBase.h
Normal file
57
src/input/RotaryEncoderInterruptBase.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "SinglePortPlugin.h" // TODO: what header file to include?
|
||||
#include "InputBroker.h"
|
||||
|
||||
enum RotaryEncoderInterruptBaseStateType
|
||||
{
|
||||
ROTARY_EVENT_OCCURRED,
|
||||
ROTARY_EVENT_CLEARED
|
||||
};
|
||||
|
||||
enum RotaryEncoderInterruptBaseActionType
|
||||
{
|
||||
ROTARY_ACTION_NONE,
|
||||
ROTARY_ACTION_PRESSED,
|
||||
ROTARY_ACTION_CW,
|
||||
ROTARY_ACTION_CCW
|
||||
};
|
||||
|
||||
class RotaryEncoderInterruptBase :
|
||||
public Observable<const InputEvent *>,
|
||||
private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit RotaryEncoderInterruptBase(
|
||||
const char *name);
|
||||
void init(
|
||||
uint8_t pinA, uint8_t pinB, uint8_t pinPress,
|
||||
char eventCw, char eventCcw, char eventPressed,
|
||||
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress);
|
||||
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)());
|
||||
void intPressHandler();
|
||||
void intAHandler();
|
||||
void intBHandler();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
RotaryEncoderInterruptBaseStateType intHandler(
|
||||
bool actualPinRaising,
|
||||
int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state);
|
||||
|
||||
volatile RotaryEncoderInterruptBaseStateType rotaryStateCW = ROTARY_EVENT_CLEARED;
|
||||
volatile RotaryEncoderInterruptBaseStateType rotaryStateCCW = ROTARY_EVENT_CLEARED;
|
||||
volatile int rotaryLevelA = LOW;
|
||||
volatile int rotaryLevelB = LOW;
|
||||
volatile RotaryEncoderInterruptBaseActionType action = ROTARY_ACTION_NONE;
|
||||
|
||||
private:
|
||||
uint8_t _pinA = 0;
|
||||
uint8_t _pinB = 0;
|
||||
char _eventCw = InputEventChar_KEY_NONE;
|
||||
char _eventCcw = InputEventChar_KEY_NONE;
|
||||
char _eventPressed = InputEventChar_KEY_NONE;
|
||||
const char *_originName;
|
||||
};
|
||||
51
src/input/RotaryEncoderInterruptImpl1.cpp
Normal file
51
src/input/RotaryEncoderInterruptImpl1.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "RotaryEncoderInterruptImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
|
||||
RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
|
||||
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() :
|
||||
RotaryEncoderInterruptBase(
|
||||
"rotEnc1")
|
||||
{
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptImpl1::init()
|
||||
{
|
||||
if (!radioConfig.preferences.rotary1_enabled)
|
||||
{
|
||||
// Input device is disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pinA = radioConfig.preferences.rotary1_pin_a;
|
||||
uint8_t pinB = radioConfig.preferences.rotary1_pin_b;
|
||||
uint8_t pinPress = radioConfig.preferences.rotary1_pin_press;
|
||||
char eventCw =
|
||||
static_cast<char>(radioConfig.preferences.rotary1_event_cw);
|
||||
char eventCcw =
|
||||
static_cast<char>(radioConfig.preferences.rotary1_event_ccw);
|
||||
char eventPressed =
|
||||
static_cast<char>(radioConfig.preferences.rotary1_event_press);
|
||||
|
||||
//radioConfig.preferences.ext_notification_module_output
|
||||
RotaryEncoderInterruptBase::init(
|
||||
pinA, pinB, pinPress,
|
||||
eventCw, eventCcw, eventPressed,
|
||||
RotaryEncoderInterruptImpl1::handleIntA,
|
||||
RotaryEncoderInterruptImpl1::handleIntB,
|
||||
RotaryEncoderInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptImpl1::handleIntA()
|
||||
{
|
||||
rotaryEncoderInterruptImpl1->intAHandler();
|
||||
}
|
||||
void RotaryEncoderInterruptImpl1::handleIntB()
|
||||
{
|
||||
rotaryEncoderInterruptImpl1->intBHandler();
|
||||
}
|
||||
void RotaryEncoderInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
rotaryEncoderInterruptImpl1->intPressHandler();
|
||||
}
|
||||
22
src/input/RotaryEncoderInterruptImpl1.h
Normal file
22
src/input/RotaryEncoderInterruptImpl1.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "RotaryEncoderInterruptBase.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 RotaryEncoderInterruptImpl1 :
|
||||
public RotaryEncoderInterruptBase
|
||||
{
|
||||
public:
|
||||
RotaryEncoderInterruptImpl1();
|
||||
void init();
|
||||
static void handleIntA();
|
||||
static void handleIntB();
|
||||
static void handleIntPressed();
|
||||
};
|
||||
|
||||
extern RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
353
src/main.cpp
353
src/main.cpp
@@ -18,10 +18,12 @@
|
||||
#include "concurrency/Periodic.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "plugins/Plugins.h"
|
||||
#include "modules/Modules.h"
|
||||
#include "sleep.h"
|
||||
#include "shutdown.h"
|
||||
#include "target_specific.h"
|
||||
#include <OneButton.h>
|
||||
#include "debug/i2cScan.h"
|
||||
#include "debug/axpDebug.h"
|
||||
#include <Wire.h>
|
||||
// #include <driver/rtc_io.h>
|
||||
|
||||
@@ -42,9 +44,8 @@
|
||||
#include "SX1268Interface.h"
|
||||
#include "LLCC68Interface.h"
|
||||
|
||||
#ifdef NRF52_SERIES
|
||||
#include "variant.h"
|
||||
#endif
|
||||
#include "ButtonThread.h"
|
||||
#include "PowerFSMThread.h"
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
@@ -67,50 +68,6 @@ bool axp192_found;
|
||||
|
||||
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Application
|
||||
// -----------------------------------------------------------------------------
|
||||
#ifndef NO_WIRE
|
||||
void scanI2Cdevice(void)
|
||||
{
|
||||
byte err, addr;
|
||||
int nDevices = 0;
|
||||
for (addr = 1; addr < 127; addr++) {
|
||||
Wire.beginTransmission(addr);
|
||||
err = Wire.endTransmission();
|
||||
if (err == 0) {
|
||||
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
|
||||
|
||||
nDevices++;
|
||||
|
||||
if (addr == SSD1306_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("ssd1306 display found\n");
|
||||
}
|
||||
if (addr == ST7567_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("st7567 display found\n");
|
||||
}
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
if (addr == AXP192_SLAVE_ADDRESS) {
|
||||
axp192_found = true;
|
||||
DEBUG_MSG("axp192 PMU found\n");
|
||||
}
|
||||
#endif
|
||||
} else if (err == 4) {
|
||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
DEBUG_MSG("No I2C devices found\n");
|
||||
else
|
||||
DEBUG_MSG("done\n");
|
||||
}
|
||||
#else
|
||||
void scanI2Cdevice(void) {}
|
||||
#endif
|
||||
|
||||
const char *getDeviceName()
|
||||
{
|
||||
uint8_t dmac[6];
|
||||
@@ -136,232 +93,6 @@ static int32_t ledBlinker()
|
||||
|
||||
uint32_t timeLastPowered = 0;
|
||||
|
||||
/// Wrapper to convert our powerFSM stuff into a 'thread'
|
||||
class PowerFSMThread : public OSThread
|
||||
{
|
||||
public:
|
||||
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
|
||||
PowerFSMThread() : OSThread("PowerFSM") {}
|
||||
|
||||
protected:
|
||||
int32_t runOnce()
|
||||
{
|
||||
powerFSM.run_machine();
|
||||
|
||||
/// 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();
|
||||
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
|
||||
|
||||
if (powerStatus->getHasUSB()) {
|
||||
timeLastPowered = millis();
|
||||
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 &&
|
||||
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered
|
||||
powerFSM.trigger(EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Watch a GPIO and if we get an IRQ, wake the main thread.
|
||||
* Use to add wake on button press
|
||||
*/
|
||||
void wakeOnIrq(int irq, int mode)
|
||||
{
|
||||
attachInterrupt(
|
||||
irq,
|
||||
[] {
|
||||
BaseType_t higherWake = 0;
|
||||
mainDelay.interruptFromISR(&higherWake);
|
||||
},
|
||||
FALLING);
|
||||
}
|
||||
|
||||
class ButtonThread : public OSThread
|
||||
{
|
||||
// Prepare for button presses
|
||||
#ifdef BUTTON_PIN
|
||||
OneButton userButton;
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
OneButton userButtonAlt;
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
OneButton userButtonTouch;
|
||||
#endif
|
||||
static bool shutdown_on_long_stop;
|
||||
|
||||
public:
|
||||
static uint32_t longPressTime;
|
||||
|
||||
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
|
||||
ButtonThread() : OSThread("Button")
|
||||
{
|
||||
#ifdef BUTTON_PIN
|
||||
userButton = OneButton(BUTTON_PIN, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButton.attachClick(userButtonPressed);
|
||||
userButton.attachDuringLongPress(userButtonPressedLong);
|
||||
userButton.attachDoubleClick(userButtonDoublePressed);
|
||||
userButton.attachMultiClick(userButtonMultiPressed);
|
||||
userButton.attachLongPressStart(userButtonPressedLongStart);
|
||||
userButton.attachLongPressStop(userButtonPressedLongStop);
|
||||
wakeOnIrq(BUTTON_PIN, FALLING);
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButtonAlt.attachClick(userButtonPressed);
|
||||
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
|
||||
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
|
||||
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
|
||||
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
|
||||
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
|
||||
#endif
|
||||
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN_TOUCH, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButtonTouch.attachClick(touchPressed);
|
||||
userButtonTouch.attachDuringLongPress(touchPressedLong);
|
||||
userButtonTouch.attachDoubleClick(touchDoublePressed);
|
||||
userButtonTouch.attachLongPressStart(touchPressedLongStart);
|
||||
userButtonTouch.attachLongPressStop(touchPressedLongStop);
|
||||
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
/// If the button is pressed we suppress CPU sleep until release
|
||||
int32_t runOnce()
|
||||
{
|
||||
canSleep = true; // Assume we should not keep the board awake
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
userButton.tick();
|
||||
canSleep &= userButton.isIdle();
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
userButtonAlt.tick();
|
||||
canSleep &= userButtonAlt.isIdle();
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
userButtonTouch.tick();
|
||||
canSleep &= userButtonTouch.isIdle();
|
||||
#endif
|
||||
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
|
||||
// else DEBUG_MSG("sleep ok\n");
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
private:
|
||||
static void touchPressed()
|
||||
{
|
||||
screen->forceDisplay();
|
||||
DEBUG_MSG("touch press!\n");
|
||||
}
|
||||
static void touchDoublePressed()
|
||||
{
|
||||
DEBUG_MSG("touch double press!\n");
|
||||
}
|
||||
static void touchPressedLong()
|
||||
{
|
||||
DEBUG_MSG("touch press long!\n");
|
||||
}
|
||||
static void touchDoublePressedLong()
|
||||
{
|
||||
DEBUG_MSG("touch double pressed!\n");
|
||||
}
|
||||
static void touchPressedLongStart()
|
||||
{
|
||||
DEBUG_MSG("touch long press start!\n");
|
||||
}
|
||||
static void touchPressedLongStop()
|
||||
{
|
||||
DEBUG_MSG("touch long press stop!\n");
|
||||
}
|
||||
|
||||
|
||||
static void userButtonPressed()
|
||||
{
|
||||
// DEBUG_MSG("press!\n");
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
}
|
||||
static void userButtonPressedLong()
|
||||
{
|
||||
// DEBUG_MSG("Long press!\n");
|
||||
screen->adjustBrightness();
|
||||
|
||||
// If user button is held down for 5 seconds, shutdown the device.
|
||||
if (millis() - longPressTime > 5 * 1000) {
|
||||
#ifdef TBEAM_V10
|
||||
if (axp192_found == true) {
|
||||
setLed(false);
|
||||
power->shutdown();
|
||||
}
|
||||
#elif NRF52_SERIES
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
if (!shutdown_on_long_stop) {
|
||||
DEBUG_MSG("Shutdown from long press");
|
||||
playBeep();
|
||||
ledOff(PIN_LED1);
|
||||
ledOff(PIN_LED2);
|
||||
shutdown_on_long_stop = true;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
|
||||
}
|
||||
}
|
||||
|
||||
static void userButtonDoublePressed()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
disablePin();
|
||||
#elif defined(HAS_EINK)
|
||||
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void userButtonMultiPressed()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
clearNVS();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void userButtonPressedLongStart()
|
||||
{
|
||||
DEBUG_MSG("Long press start!\n");
|
||||
longPressTime = millis();
|
||||
}
|
||||
|
||||
static void userButtonPressedLongStop()
|
||||
{
|
||||
DEBUG_MSG("Long press stop!\n");
|
||||
longPressTime = 0;
|
||||
if (shutdown_on_long_stop) {
|
||||
playShutdownMelody();
|
||||
power->shutdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool ButtonThread::shutdown_on_long_stop = false;
|
||||
|
||||
static Periodic *ledPeriodic;
|
||||
@@ -507,22 +238,6 @@ void setup()
|
||||
|
||||
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
|
||||
|
||||
#ifdef GENIEBLOCKS
|
||||
Im intentionally breaking your build so you see this note.Feel free to revert if not correct.I think you can
|
||||
remove this GPS_RESET_N code by instead defining PIN_GPS_RESET and
|
||||
use the shared code in GPS.cpp instead.- geeksville
|
||||
|
||||
// gps setup
|
||||
pinMode(GPS_RESET_N, OUTPUT);
|
||||
pinMode(GPS_EXTINT, OUTPUT);
|
||||
digitalWrite(GPS_RESET_N, HIGH);
|
||||
digitalWrite(GPS_EXTINT, LOW);
|
||||
// battery setup
|
||||
// If we want to read battery level, we need to set BATTERY_EN_PIN pin to low.
|
||||
// ToDo: For low power consumption after read battery level, set that pin to high.
|
||||
pinMode(BATTERY_EN_PIN, OUTPUT);
|
||||
digitalWrite(BATTERY_EN_PIN, LOW);
|
||||
#endif
|
||||
gps = createGps();
|
||||
|
||||
if (gps)
|
||||
@@ -534,8 +249,8 @@ void setup()
|
||||
|
||||
service.init();
|
||||
|
||||
// Now that the mesh service is created, create any plugins
|
||||
setupPlugins();
|
||||
// Now that the mesh service is created, create any modules
|
||||
setupModules();
|
||||
|
||||
// Do this after service.init (because that clears error_code)
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
@@ -658,16 +373,16 @@ void setup()
|
||||
|
||||
if (!rIf)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_NoRadio);
|
||||
else
|
||||
else{
|
||||
router->addInterface(rIf);
|
||||
|
||||
// Calculate and save the bit rate to myNodeInfo
|
||||
// TODO: This needs to be added what ever method changes the channel from the phone.
|
||||
myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) /
|
||||
(float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))
|
||||
) * 1000;
|
||||
DEBUG_MSG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
|
||||
|
||||
// Calculate and save the bit rate to myNodeInfo
|
||||
// TODO: This needs to be added what ever method changes the channel from the phone.
|
||||
myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) /
|
||||
(float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))
|
||||
) * 1000;
|
||||
DEBUG_MSG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
|
||||
}
|
||||
|
||||
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
|
||||
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
|
||||
@@ -677,40 +392,8 @@ void setup()
|
||||
setCPUFast(false); // 80MHz is fine for our slow peripherals
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Turn off for now
|
||||
|
||||
uint32_t axpDebugRead()
|
||||
{
|
||||
axp.debugCharging();
|
||||
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
|
||||
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
|
||||
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
|
||||
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
|
||||
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
|
||||
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
|
||||
DEBUG_MSG("is charging %d\n", axp.isChargeing());
|
||||
|
||||
return 30 * 1000;
|
||||
}
|
||||
|
||||
Periodic axpDebugOutput(axpDebugRead);
|
||||
axpDebugOutput.setup();
|
||||
#endif
|
||||
|
||||
uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
|
||||
|
||||
void rebootCheck()
|
||||
{
|
||||
if (rebootAtMsec && millis() > rebootAtMsec) {
|
||||
#ifndef NO_ESP32
|
||||
DEBUG_MSG("Rebooting for update\n");
|
||||
ESP.restart();
|
||||
#else
|
||||
DEBUG_MSG("FIXME implement reboot for this platform");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client)
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
@@ -730,7 +413,7 @@ void loop()
|
||||
#ifdef NRF52_SERIES
|
||||
nrf52Loop();
|
||||
#endif
|
||||
rebootCheck();
|
||||
powerCommandsCheck();
|
||||
|
||||
// For debugging
|
||||
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "PowerStatus.h"
|
||||
#include "graphics/Screen.h"
|
||||
|
||||
extern uint8_t screen_found;
|
||||
extern bool axp192_found;
|
||||
extern bool isCharging;
|
||||
extern bool isUSBPowered;
|
||||
@@ -20,10 +21,13 @@ extern graphics::Screen *screen;
|
||||
// Return a human readable string of the form "Meshtastic_ab13"
|
||||
const char *getDeviceName();
|
||||
|
||||
extern uint32_t timeLastPowered;
|
||||
|
||||
extern uint32_t rebootAtMsec;
|
||||
extern uint32_t shutdownAtMsec;
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop();
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds();
|
||||
|
||||
@@ -247,7 +247,7 @@ static int mem_test(uint32_t *_start, size_t len, bool doRead = true, bool doWri
|
||||
{
|
||||
volatile uint32_t *addr;
|
||||
volatile uint32_t *start = (volatile uint32_t *)_start;
|
||||
volatile uint32_t *end = start + len / sizeof(uint32_t);
|
||||
const volatile uint32_t *end = start + len / sizeof(uint32_t);
|
||||
uint32_t pattern = 0;
|
||||
uint32_t val;
|
||||
uint32_t readback;
|
||||
@@ -315,4 +315,4 @@ void doMemTest()
|
||||
assert(0); // FIXME report error better
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
|
||||
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
|
||||
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
|
||||
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01};
|
||||
|
||||
Channels channels;
|
||||
|
||||
@@ -84,10 +84,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
|
||||
Channel &ch = getByIndex(chIndex);
|
||||
ChannelSettings &channelSettings = ch.settings;
|
||||
|
||||
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
|
||||
// channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide
|
||||
// bandwidth so incompatible radios can talk together
|
||||
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
|
||||
channelSettings.modem_config = ChannelSettings_ModemConfig_LongFast; // Default to Long Range & Fast
|
||||
|
||||
channelSettings.tx_power = 0; // default
|
||||
uint8_t defaultpskIndex = 1;
|
||||
@@ -102,7 +99,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
|
||||
CryptoKey Channels::getKey(ChannelIndex chIndex)
|
||||
{
|
||||
Channel &ch = getByIndex(chIndex);
|
||||
ChannelSettings &channelSettings = ch.settings;
|
||||
const ChannelSettings &channelSettings = ch.settings;
|
||||
assert(ch.has_settings);
|
||||
|
||||
CryptoKey k;
|
||||
@@ -206,7 +203,7 @@ void Channels::setChannel(const Channel &c)
|
||||
const char *Channels::getName(size_t chIndex)
|
||||
{
|
||||
// Convert the short "" representation for Default into a usable string
|
||||
ChannelSettings &channelSettings = getByIndex(chIndex).settings;
|
||||
const ChannelSettings &channelSettings = getByIndex(chIndex).settings;
|
||||
const char *channelName = channelSettings.name;
|
||||
if (!*channelName) { // emptystring
|
||||
// Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case
|
||||
@@ -216,24 +213,27 @@ const char *Channels::getName(size_t chIndex)
|
||||
channelName = "Unset";
|
||||
else
|
||||
switch (channelSettings.modem_config) {
|
||||
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
|
||||
case ChannelSettings_ModemConfig_ShortSlow:
|
||||
channelName = "ShortSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
|
||||
case ChannelSettings_ModemConfig_ShortFast:
|
||||
channelName = "ShortFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
|
||||
channelName = "LongFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||
channelName = "LongSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
|
||||
case ChannelSettings_ModemConfig_MidSlow:
|
||||
channelName = "MediumSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
|
||||
case ChannelSettings_ModemConfig_MidFast:
|
||||
channelName = "MediumFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_LongFast:
|
||||
channelName = "LongFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_LongSlow:
|
||||
channelName = "LongSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_VLongSlow:
|
||||
channelName = "VLongSlow";
|
||||
break;
|
||||
default:
|
||||
channelName = "Invalid";
|
||||
break;
|
||||
|
||||
@@ -26,9 +26,12 @@ class Channels
|
||||
ChannelIndex activeChannelIndex = 0;
|
||||
|
||||
/// the precomputed hashes for each of our channels, or -1 for invalid
|
||||
int16_t hashes[MAX_NUM_CHANNELS];
|
||||
int16_t hashes[MAX_NUM_CHANNELS] = {};
|
||||
|
||||
public:
|
||||
|
||||
Channels() {}
|
||||
|
||||
/// Well known channel names
|
||||
static const char *adminChannel, *gpioChannel, *serialChannel;
|
||||
|
||||
@@ -134,4 +137,4 @@ class Channels
|
||||
};
|
||||
|
||||
/// Singleton channel table
|
||||
extern Channels channels;
|
||||
extern Channels channels;
|
||||
|
||||
@@ -20,9 +20,9 @@ class CryptoEngine
|
||||
{
|
||||
protected:
|
||||
/** Our per packet nonce */
|
||||
uint8_t nonce[16];
|
||||
uint8_t nonce[16] = {0};
|
||||
|
||||
CryptoKey key;
|
||||
CryptoKey key = {};
|
||||
|
||||
public:
|
||||
virtual ~CryptoEngine() {}
|
||||
|
||||
@@ -8,14 +8,14 @@ class DSRRouter : public ReliableRouter
|
||||
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
|
||||
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
|
||||
*/
|
||||
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
|
||||
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
|
||||
|
||||
/**
|
||||
* Send a packet on a suitable interface. This routine will
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
* If the txmit queue is full it might return an error
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
virtual ErrorCode send(MeshPacket *p) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -77,4 +77,4 @@ class DSRRouter : public ReliableRouter
|
||||
* when the discovery is complete.
|
||||
*/
|
||||
void startDiscovery(NodeNum dest);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "configuration.h"
|
||||
#include "FloodingRouter.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
FloodingRouter::FloodingRouter() {}
|
||||
@@ -27,11 +27,41 @@ bool FloodingRouter::shouldFilterReceived(MeshPacket *p)
|
||||
return Router::shouldFilterReceived(p);
|
||||
}
|
||||
|
||||
bool FloodingRouter::inRangeOfRouter()
|
||||
{
|
||||
|
||||
uint32_t maximum_router_sec = 300;
|
||||
|
||||
// FIXME : Scale minimum_snr to accomodate different modem configurations.
|
||||
float minimum_snr = 2;
|
||||
|
||||
for (int i = 0; i < myNodeInfo.router_count; i++) {
|
||||
// A router has been seen and the heartbeat was heard within the last 300 seconds
|
||||
if (
|
||||
((myNodeInfo.router_sec[i] > 0) && (myNodeInfo.router_sec[i] < maximum_router_sec)) &&
|
||||
(myNodeInfo.router_snr[i] > minimum_snr)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
{
|
||||
// If a broadcast, possibly _also_ send copies out into the mesh.
|
||||
// (FIXME, do something smarter than naive flooding here)
|
||||
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && getFrom(p) != getNodeNum()) {
|
||||
bool rebroadcastPacket = true;
|
||||
|
||||
if (radioConfig.preferences.role == Role_Repeater || radioConfig.preferences.role == Role_Router) {
|
||||
rebroadcastPacket = true;
|
||||
|
||||
} else if ((radioConfig.preferences.role == Role_Default) && inRangeOfRouter()) {
|
||||
DEBUG_MSG("Role_Default - rx_snr > 13\n");
|
||||
|
||||
rebroadcastPacket = false;
|
||||
}
|
||||
|
||||
if ((p->to == NODENUM_BROADCAST) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum() && rebroadcastPacket)) {
|
||||
if (p->id != 0) {
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
* If the txmit queue is full it might return an error
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
virtual ErrorCode send(MeshPacket *p) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -50,10 +50,18 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p);
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) override;
|
||||
|
||||
/**
|
||||
* Are we in range of a router?
|
||||
*
|
||||
* "range" here may not be the right term.
|
||||
* @return true if we're in range of a router
|
||||
*/
|
||||
virtual bool inRangeOfRouter();
|
||||
|
||||
/**
|
||||
* Look for broadcasts we need to rebroadcast
|
||||
*/
|
||||
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
|
||||
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
|
||||
};
|
||||
|
||||
@@ -58,7 +58,7 @@ template <class T> class MemoryDynamic : public Allocator<T>
|
||||
{
|
||||
public:
|
||||
/// Return a buffer for use by others
|
||||
virtual void release(T *p)
|
||||
virtual void release(T *p) override
|
||||
{
|
||||
assert(p);
|
||||
free(p);
|
||||
@@ -66,7 +66,7 @@ template <class T> class MemoryDynamic : public Allocator<T>
|
||||
|
||||
protected:
|
||||
// Alloc some storage
|
||||
virtual T *alloc(TickType_t maxWait)
|
||||
virtual T *alloc(TickType_t maxWait) override
|
||||
{
|
||||
T *p = (T *)malloc(sizeof(T));
|
||||
assert(p);
|
||||
@@ -87,7 +87,7 @@ template <class T> class MemoryPool : public Allocator<T>
|
||||
size_t maxElements;
|
||||
|
||||
public:
|
||||
MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
|
||||
explicit MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
|
||||
{
|
||||
buf = new T[maxElements];
|
||||
|
||||
@@ -99,7 +99,7 @@ template <class T> class MemoryPool : public Allocator<T>
|
||||
~MemoryPool() { delete[] buf; }
|
||||
|
||||
/// Return a buffer for use by others
|
||||
virtual void release(T *p)
|
||||
void release(T *p)
|
||||
{
|
||||
assert(p >= buf &&
|
||||
(size_t)(p - buf) <
|
||||
|
||||
@@ -18,7 +18,7 @@ class MeshPacketQueue
|
||||
bool replaceLowerPriorityPacket(MeshPacket *mp);
|
||||
|
||||
public:
|
||||
MeshPacketQueue(size_t _maxLen);
|
||||
explicit MeshPacketQueue(size_t _maxLen);
|
||||
|
||||
/** enqueue a packet, return false if full */
|
||||
bool enqueue(MeshPacket *p);
|
||||
@@ -30,4 +30,4 @@ class MeshPacketQueue
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
|
||||
MeshPacket *remove(NodeNum from, PacketId id);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
#include "Channels.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
#include "modules/RoutingModule.h"
|
||||
#include <assert.h>
|
||||
|
||||
std::vector<MeshPlugin *> *MeshPlugin::plugins;
|
||||
std::vector<MeshPlugin *> *MeshPlugin::modules;
|
||||
|
||||
const MeshPacket *MeshPlugin::currentRequest;
|
||||
|
||||
/**
|
||||
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
|
||||
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
|
||||
* the RoutingPlugin to avoid sending redundant acks
|
||||
*/
|
||||
MeshPacket *MeshPlugin::currentReply;
|
||||
@@ -19,17 +19,17 @@ MeshPacket *MeshPlugin::currentReply;
|
||||
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
|
||||
{
|
||||
// Can't trust static initalizer order, so we check each time
|
||||
if (!plugins)
|
||||
plugins = new std::vector<MeshPlugin *>();
|
||||
if (!modules)
|
||||
modules = new std::vector<MeshPlugin *>();
|
||||
|
||||
plugins->push_back(this);
|
||||
modules->push_back(this);
|
||||
}
|
||||
|
||||
void MeshPlugin::setup() {}
|
||||
|
||||
MeshPlugin::~MeshPlugin()
|
||||
{
|
||||
assert(0); // FIXME - remove from list of plugins once someone needs this feature
|
||||
assert(0); // FIXME - remove from list of modules once someone needs this feature
|
||||
}
|
||||
|
||||
MeshPacket *MeshPlugin::allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
@@ -68,10 +68,10 @@ MeshPacket *MeshPlugin::allocErrorResponse(Routing_Error err, const MeshPacket *
|
||||
|
||||
void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
{
|
||||
// DEBUG_MSG("In call plugins\n");
|
||||
bool pluginFound = false;
|
||||
// DEBUG_MSG("In call modules\n");
|
||||
bool moduleFound = false;
|
||||
|
||||
// We now allow **encrypted** packets to pass through the plugins
|
||||
// We now allow **encrypted** packets to pass through the modules
|
||||
bool isDecoded = mp.which_payloadVariant == MeshPacket_decoded_tag;
|
||||
|
||||
currentReply = NULL; // No reply yet
|
||||
@@ -80,12 +80,12 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
auto ourNodeNum = nodeDB.getNodeNum();
|
||||
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
|
||||
|
||||
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
|
||||
pi.currentRequest = ∓
|
||||
|
||||
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||
/// We only call modules that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||
|
||||
if ((src == RX_SRC_LOCAL) && !(pi.loopbackOk)) {
|
||||
@@ -96,15 +96,15 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
|
||||
|
||||
if (wantsPacket) {
|
||||
DEBUG_MSG("Plugin '%s' wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
DEBUG_MSG("Module '%s' wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
|
||||
pluginFound = true;
|
||||
moduleFound = true;
|
||||
|
||||
/// received channel (or NULL if not decoded)
|
||||
Channel *ch = isDecoded ? &channels.getByIndex(mp.channel) : NULL;
|
||||
|
||||
/// Is the channel this packet arrived on acceptable? (security check)
|
||||
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel plugins
|
||||
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel modules
|
||||
|
||||
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and it needs to
|
||||
/// to be able to fetch the initial admin packets without yet knowing any channels.
|
||||
@@ -128,7 +128,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
ProcessMessage handled = pi.handleReceived(mp);
|
||||
|
||||
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious
|
||||
// sniffing) also: we only let the one plugin send a reply, once that happens, remaining plugins are not
|
||||
// sniffing) also: we only let the one module send a reply, once that happens, remaining modules are not
|
||||
// considered
|
||||
|
||||
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary
|
||||
@@ -137,9 +137,9 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
// any other node.
|
||||
if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
|
||||
pi.sendResponse(mp);
|
||||
DEBUG_MSG("Plugin '%s' sent a response\n", pi.name);
|
||||
DEBUG_MSG("Module '%s' sent a response\n", pi.name);
|
||||
} else {
|
||||
DEBUG_MSG("Plugin '%s' considered\n", pi.name);
|
||||
DEBUG_MSG("Module '%s' considered\n", pi.name);
|
||||
}
|
||||
|
||||
// If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks
|
||||
@@ -150,7 +150,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
}
|
||||
|
||||
if (handled == ProcessMessage::STOP) {
|
||||
DEBUG_MSG("Plugin '%s' handled and skipped other processing\n", pi.name);
|
||||
DEBUG_MSG("Module '%s' handled and skipped other processing\n", pi.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -173,13 +173,13 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
|
||||
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
|
||||
// bad.
|
||||
routingPlugin->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
|
||||
routingModule->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pluginFound)
|
||||
DEBUG_MSG("No plugins interested in portnum=%d, src=%s\n",
|
||||
mp.decoded.portnum,
|
||||
if (!moduleFound)
|
||||
DEBUG_MSG("No modules interested in portnum=%d, src=%s\n",
|
||||
mp.decoded.portnum,
|
||||
(src == RX_SRC_LOCAL) ? "LOCAL":"REMOTE");
|
||||
}
|
||||
|
||||
@@ -201,8 +201,8 @@ void MeshPlugin::sendResponse(const MeshPacket &req)
|
||||
setReplyTo(r, req);
|
||||
currentReply = r;
|
||||
} else {
|
||||
// Ignore - this is now expected behavior for routing plugin (because it ignores some replies)
|
||||
// DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
|
||||
// Ignore - this is now expected behavior for routing module (because it ignores some replies)
|
||||
// DEBUG_MSG("WARNING: Client requested response but this module did not provide\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,16 +222,61 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to)
|
||||
p->decoded.request_id = to.id;
|
||||
}
|
||||
|
||||
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames()
|
||||
std::vector<MeshPlugin *> MeshPlugin::GetMeshModulesWithUIFrames()
|
||||
{
|
||||
|
||||
std::vector<MeshPlugin *> pluginsWithUIFrames;
|
||||
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
if (pi.wantUIFrame()) {
|
||||
DEBUG_MSG("Plugin wants a UI Frame\n");
|
||||
pluginsWithUIFrames.push_back(&pi);
|
||||
std::vector<MeshPlugin *> modulesWithUIFrames;
|
||||
if (modules) {
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
if (pi.wantUIFrame()) {
|
||||
DEBUG_MSG("Module wants a UI Frame\n");
|
||||
modulesWithUIFrames.push_back(&pi);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pluginsWithUIFrames;
|
||||
return modulesWithUIFrames;
|
||||
}
|
||||
|
||||
void MeshPlugin::observeUIEvents(
|
||||
Observer<const UIFrameEvent *> *observer)
|
||||
{
|
||||
if (modules) {
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
Observable<const UIFrameEvent *> *observable =
|
||||
pi.getUIFrameObservable();
|
||||
if (observable != NULL) {
|
||||
DEBUG_MSG("Module wants a UI Frame\n");
|
||||
observer->observe(observable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdminMessageHandleResult MeshPlugin::handleAdminMessageForAllPlugins(const MeshPacket &mp, AdminMessage *request, AdminMessage *response)
|
||||
{
|
||||
AdminMessageHandleResult handled = AdminMessageHandleResult::NOT_HANDLED;
|
||||
if (modules) {
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
AdminMessageHandleResult h = pi.handleAdminMessageForModule(mp, request, response);
|
||||
if (h == AdminMessageHandleResult::HANDLED_WITH_RESPONSE)
|
||||
{
|
||||
// In case we have a response it always has priority.
|
||||
DEBUG_MSG("Reply prepared by module '%s' of variant: %d\n",
|
||||
pi.name,
|
||||
response->which_variant);
|
||||
handled = h;
|
||||
}
|
||||
else if ((handled != AdminMessageHandleResult::HANDLED_WITH_RESPONSE) &&
|
||||
(h == AdminMessageHandleResult::HANDLED))
|
||||
{
|
||||
// In case the message is handled it should be populated, but will not overwrite
|
||||
// a result with response.
|
||||
handled = h;
|
||||
}
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
@@ -21,19 +21,40 @@ enum class ProcessMessage
|
||||
STOP = 1,
|
||||
};
|
||||
|
||||
/** A baseclass for any mesh "plugin".
|
||||
/**
|
||||
* Used by modules to return the result of the AdminMessage handling.
|
||||
* If request is handled, then module should return HANDLED,
|
||||
* If response is also prepared for the request, then HANDLED_WITH_RESPONSE
|
||||
* should be returned.
|
||||
*/
|
||||
enum class AdminMessageHandleResult
|
||||
{
|
||||
NOT_HANDLED = 0,
|
||||
HANDLED = 1,
|
||||
HANDLED_WITH_RESPONSE = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* This struct is used by Screen to figure out whether screen frame should be updated.
|
||||
*/
|
||||
typedef struct _UIFrameEvent {
|
||||
bool frameChanged;
|
||||
bool needRedraw;
|
||||
} UIFrameEvent;
|
||||
|
||||
/** A baseclass for any mesh "module".
|
||||
*
|
||||
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||
* A module allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||
*
|
||||
* A key concept for this is that your plugin should use a particular "portnum" for each message type you want to receive
|
||||
* A key concept for this is that your module should use a particular "portnum" for each message type you want to receive
|
||||
* and handle.
|
||||
*
|
||||
* Interally we use plugins to implement the core meshtastic text messaging and gps position sharing features. You
|
||||
* can use these classes as examples for how to write your own custom plugin. See here: (FIXME)
|
||||
* Interally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
|
||||
* can use these classes as examples for how to write your own custom module. See here: (FIXME)
|
||||
*/
|
||||
class MeshPlugin
|
||||
{
|
||||
static std::vector<MeshPlugin *> *plugins;
|
||||
static std::vector<MeshPlugin *> *modules;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
@@ -47,24 +68,27 @@ class MeshPlugin
|
||||
*/
|
||||
static void callPlugins(const MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
||||
|
||||
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
|
||||
static std::vector<MeshPlugin *> GetMeshModulesWithUIFrames();
|
||||
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
|
||||
static AdminMessageHandleResult handleAdminMessageForAllPlugins(
|
||||
const MeshPacket &mp, AdminMessage *request, AdminMessage *response);
|
||||
#ifndef NO_SCREEN
|
||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
|
||||
#endif
|
||||
protected:
|
||||
const char *name;
|
||||
|
||||
/** Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
|
||||
/** Most modules only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
|
||||
recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those
|
||||
plugins can set this to true and their handleReceived() will be called for every packet.
|
||||
modules can set this to true and their handleReceived() will be called for every packet.
|
||||
*/
|
||||
bool isPromiscuous = false;
|
||||
|
||||
/** Also receive a copy of LOCALLY GENERATED messages - most plugins should leave
|
||||
/** Also receive a copy of LOCALLY GENERATED messages - most modules should leave
|
||||
* this setting disabled - see issue #877 */
|
||||
bool loopbackOk = false;
|
||||
|
||||
/** Most plugins only understand decrypted packets. For plugins that also want to see encrypted packets, they should set this
|
||||
/** Most modules only understand decrypted packets. For modules that also want to see encrypted packets, they should set this
|
||||
* flag */
|
||||
bool encryptedOk = false;
|
||||
|
||||
@@ -77,11 +101,11 @@ class MeshPlugin
|
||||
const char *boundChannel = NULL;
|
||||
|
||||
/**
|
||||
* If this plugin is currently handling a request currentRequest will be preset
|
||||
* If this module is currently handling a request currentRequest will be preset
|
||||
* to the packet with the request. This is mostly useful for reply handlers.
|
||||
*
|
||||
* Note: this can be static because we are guaranteed to be processing only one
|
||||
* plugin at a time.
|
||||
* plumodulegin at a time.
|
||||
*/
|
||||
static const MeshPacket *currentRequest;
|
||||
|
||||
@@ -91,7 +115,7 @@ class MeshPlugin
|
||||
MeshPacket *myReply = NULL;
|
||||
|
||||
/**
|
||||
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
|
||||
* Initialize your module. This setup function is called once after all hardware and mesh protocol layers have
|
||||
* been initialized
|
||||
*/
|
||||
virtual void setup();
|
||||
@@ -119,16 +143,30 @@ class MeshPlugin
|
||||
* @return true if you want to be alloced a UI screen frame
|
||||
*/
|
||||
virtual bool wantUIFrame() { return false; }
|
||||
virtual Observable<const UIFrameEvent *>* getUIFrameObservable() { return NULL; }
|
||||
|
||||
MeshPacket *allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
|
||||
|
||||
/// Send an error response for the specified packet.
|
||||
MeshPacket *allocErrorResponse(Routing_Error err, const MeshPacket *p);
|
||||
|
||||
/**
|
||||
* @brief An admin message arrived to AdminModule. Module was asked whether it want to handle the request.
|
||||
*
|
||||
* @param mp The mesh packet arrived.
|
||||
* @param request The AdminMessage request extracted from the packet.
|
||||
* @param response The prepared response
|
||||
* @return AdminMessageHandleResult
|
||||
* HANDLED if message was handled
|
||||
* HANDLED_WITH_RESPONSE if a response is also prepared and to be sent.
|
||||
*/
|
||||
virtual AdminMessageHandleResult handleAdminMessageForModule(
|
||||
const MeshPacket &mp, AdminMessage *request, AdminMessage *response) { return AdminMessageHandleResult::NOT_HANDLED; };
|
||||
|
||||
private:
|
||||
/**
|
||||
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
|
||||
* the RoutingPlugin to avoid sending redundant acks
|
||||
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
|
||||
* the RoutingModule to avoid sending redundant acks
|
||||
*/
|
||||
static MeshPacket *currentReply;
|
||||
|
||||
@@ -144,4 +182,4 @@ class MeshPlugin
|
||||
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
||||
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
||||
*/
|
||||
void setReplyTo(MeshPacket *p, const MeshPacket &to);
|
||||
void setReplyTo(MeshPacket *p, const MeshPacket &to);
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
// Map from old region names to new region enums
|
||||
struct RegionInfo {
|
||||
RegionCode code;
|
||||
uint8_t numChannels;
|
||||
uint8_t powerLimit; // Or zero for not set
|
||||
float freq;
|
||||
float freqStart;
|
||||
float freqEnd;
|
||||
float dutyCycle;
|
||||
float spacing;
|
||||
uint8_t powerLimit; // Or zero for not set
|
||||
bool audioPermitted;
|
||||
bool freqSwitching;
|
||||
const char *name; // EU433 etc
|
||||
};
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#include "RTC.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/NodeInfoPlugin.h"
|
||||
#include "plugins/PositionPlugin.h"
|
||||
#include "modules/NodeInfoModule.h"
|
||||
#include "modules/PositionModule.h"
|
||||
#include "power.h"
|
||||
|
||||
/*
|
||||
@@ -115,10 +115,10 @@ void MeshService::reloadOwner()
|
||||
// DEBUG_MSG("reloadOwner()\n");
|
||||
// update our local data directly
|
||||
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
|
||||
assert(nodeInfoPlugin);
|
||||
assert(nodeInfoModule);
|
||||
// update everyone else
|
||||
if (nodeInfoPlugin)
|
||||
nodeInfoPlugin->sendOurNodeInfo();
|
||||
if (nodeInfoModule)
|
||||
nodeInfoModule->sendOurNodeInfo();
|
||||
nodeDB.saveToDisk();
|
||||
}
|
||||
|
||||
@@ -175,14 +175,14 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
assert(node);
|
||||
|
||||
if (node->has_position) {
|
||||
if (positionPlugin) {
|
||||
if (positionModule) {
|
||||
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
positionPlugin->sendOurPosition(dest, wantReplies);
|
||||
positionModule->sendOurPosition(dest, wantReplies);
|
||||
}
|
||||
} else {
|
||||
if (nodeInfoPlugin) {
|
||||
if (nodeInfoModule) {
|
||||
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
||||
nodeInfoModule->sendOurNodeInfo(dest, wantReplies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class MeshService
|
||||
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
|
||||
/// needs to keep the packet around it makes a copy
|
||||
int handleFromRadio(const MeshPacket *p);
|
||||
friend class RoutingPlugin;
|
||||
friend class RoutingModule;
|
||||
};
|
||||
|
||||
extern MeshService service;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include "FS.h"
|
||||
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "FSCommon.h"
|
||||
@@ -21,11 +19,16 @@
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "plugins/esp32/StoreForwardPlugin.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#include <Preferences.h>
|
||||
#include <nvs_flash.h>
|
||||
#endif
|
||||
|
||||
#ifdef NRF52_SERIES
|
||||
#include <bluefruit.h>
|
||||
#include <utility/bonding.h>
|
||||
#endif
|
||||
|
||||
NodeDB nodeDB;
|
||||
|
||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||
@@ -90,6 +93,16 @@ bool NodeDB::resetRadioConfig()
|
||||
#ifndef NO_ESP32
|
||||
// This will erase what's in NVS including ssl keys, persistant variables and ble pairing
|
||||
nvs_flash_erase();
|
||||
#endif
|
||||
#ifdef NRF52_SERIES
|
||||
Bluefruit.begin();
|
||||
|
||||
DEBUG_MSG("Clearing bluetooth bonds!\n");
|
||||
bond_print_list(BLE_GAP_ROLE_PERIPH);
|
||||
bond_print_list(BLE_GAP_ROLE_CENTRAL);
|
||||
|
||||
Bluefruit.Periph.clearBonds();
|
||||
Bluefruit.Central.clearBonds();
|
||||
#endif
|
||||
didFactoryReset = true;
|
||||
}
|
||||
@@ -214,35 +227,8 @@ void NodeDB::init()
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
// removed from 1.2 (though we do use old values if found)
|
||||
// We set these _after_ loading from disk - because they come from the build and are more trusted than
|
||||
// what is stored in flash
|
||||
// if (xstr(HW_VERSION)[0])
|
||||
// strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
|
||||
// else DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build
|
||||
// flag
|
||||
|
||||
// DEBUG_MSG("legacy region %d\n", devicestate.legacyRadio.preferences.region);
|
||||
if (radioConfig.preferences.region == RegionCode_Unset)
|
||||
radioConfig.preferences.region = devicestate.legacyRadio.preferences.region;
|
||||
|
||||
// Check for the old style of region code strings, if found, convert to the new enum.
|
||||
// Those strings will look like "1.0-EU433"
|
||||
if (radioConfig.preferences.region == RegionCode_Unset && strncmp(myNodeInfo.region, "1.0-", 4) == 0) {
|
||||
const char *regionStr = myNodeInfo.region + 4; // EU433 or whatever
|
||||
for (const RegionInfo *r = regions; r->code != RegionCode_Unset; r++)
|
||||
if (strcmp(r->name, regionStr) == 0) {
|
||||
radioConfig.preferences.region = r->code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
|
||||
|
||||
// hw_model is no longer stored in myNodeInfo (as of 1.2.11) - we now store it as an enum in nodeinfo
|
||||
myNodeInfo.hw_model_deprecated[0] = '\0';
|
||||
// strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model));
|
||||
|
||||
#ifndef NO_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
@@ -297,16 +283,16 @@ static const char *channelfile = "/prefs/channels.proto";
|
||||
/** Load a protobuf from a file, return true for success */
|
||||
bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
|
||||
{
|
||||
#ifdef FS
|
||||
#ifdef FSCom
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
|
||||
auto f = FS.open(filename);
|
||||
auto f = FSCom.open(filename);
|
||||
|
||||
// FIXME, temporary hack until every node in the universe is 1.2 or later - look for prefs in the old location (so we can
|
||||
// preserve region)
|
||||
if (!f && filename == preffile) {
|
||||
filename = preffileOld;
|
||||
f = FS.open(filename);
|
||||
f = FSCom.open(filename);
|
||||
}
|
||||
|
||||
bool okay = false;
|
||||
@@ -359,11 +345,11 @@ void NodeDB::loadFromDisk()
|
||||
/** Save a protobuf from a file, return true for success */
|
||||
bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct)
|
||||
{
|
||||
#ifdef FS
|
||||
#ifdef FSCom
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
String filenameTmp = filename;
|
||||
filenameTmp += ".tmp";
|
||||
auto f = FS.open(filenameTmp.c_str(), FILE_O_WRITE);
|
||||
auto f = FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
|
||||
bool okay = false;
|
||||
if (f) {
|
||||
DEBUG_MSG("Saving %s\n", filename);
|
||||
@@ -378,9 +364,9 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
f.close();
|
||||
|
||||
// brief window of risk here ;-)
|
||||
if (!FS.remove(filename))
|
||||
if (!FSCom.remove(filename))
|
||||
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
||||
if (!FS.rename(filenameTmp.c_str(), filename))
|
||||
if (!FSCom.rename(filenameTmp.c_str(), filename))
|
||||
DEBUG_MSG("Error: can't rename new pref file\n");
|
||||
} else {
|
||||
DEBUG_MSG("Can't write prefs\n");
|
||||
@@ -394,8 +380,8 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
void NodeDB::saveChannelsToDisk()
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FS
|
||||
FS.mkdir("/prefs");
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile);
|
||||
}
|
||||
@@ -404,15 +390,15 @@ void NodeDB::saveChannelsToDisk()
|
||||
void NodeDB::saveToDisk()
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FS
|
||||
FS.mkdir("/prefs");
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
bool okay = saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
|
||||
okay &= saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
|
||||
saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
|
||||
saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
|
||||
saveChannelsToDisk();
|
||||
|
||||
// remove any pre 1.2 pref files, turn on after 1.2 is in beta
|
||||
// if(okay) FS.remove(preffileOld);
|
||||
// if(okay) FSCom.remove(preffileOld);
|
||||
} else {
|
||||
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
||||
}
|
||||
@@ -459,14 +445,17 @@ size_t NodeDB::getNumOnlineNodes()
|
||||
void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
|
||||
{
|
||||
NodeInfo *info = getOrCreateNode(nodeId);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == RX_SRC_LOCAL) {
|
||||
// Local packet, fully authoritative
|
||||
DEBUG_MSG("updatePosition LOCAL pos@%x:5, time=%u, latI=%d, lonI=%d\n",
|
||||
DEBUG_MSG("updatePosition LOCAL pos@%x:5, time=%u, latI=%d, lonI=%d\n",
|
||||
p.pos_timestamp, p.time, p.latitude_i, p.longitude_i);
|
||||
info->position = p;
|
||||
|
||||
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.pos_timestamp &&
|
||||
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.pos_timestamp &&
|
||||
!p.location_source) {
|
||||
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
|
||||
// (stop-gap fix for issue #900)
|
||||
@@ -479,7 +468,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
|
||||
// recorded based on the packet rxTime
|
||||
//
|
||||
// FIXME perhaps handle RX_SRC_USER separately?
|
||||
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n",
|
||||
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n",
|
||||
nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||
|
||||
// First, back up fields that we want to protect from overwrite
|
||||
@@ -502,6 +491,9 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
|
||||
void NodeDB::updateUser(uint32_t nodeId, const User &p)
|
||||
{
|
||||
NodeInfo *info = getOrCreateNode(nodeId);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
||||
|
||||
@@ -531,6 +523,9 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||
|
||||
NodeInfo *info = getOrCreateNode(getFrom(&mp));
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard
|
||||
info->last_heard = mp.rx_time;
|
||||
@@ -557,8 +552,12 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
|
||||
NodeInfo *info = getNode(n);
|
||||
|
||||
if (!info) {
|
||||
if (*numNodes >= MAX_NUM_NODES) {
|
||||
screen->print("error: node_db full!\n");
|
||||
DEBUG_MSG("ERROR! could not create new node, node_db is full! (%d nodes)", *numNodes);
|
||||
return NULL;
|
||||
}
|
||||
// add the node
|
||||
assert(*numNodes < MAX_NUM_NODES);
|
||||
info = &nodes[(*numNodes)++];
|
||||
|
||||
// everything is missing except the nodenum
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "configuration.h"
|
||||
#include "PhoneAPI.h"
|
||||
#include "Channels.h"
|
||||
#include "GPS.h"
|
||||
@@ -6,6 +5,7 @@
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
|
||||
|
||||
@@ -24,6 +24,7 @@ class PhoneAPI
|
||||
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
|
||||
// (disconnected)
|
||||
STATE_SEND_MY_INFO, // send our my info record
|
||||
STATE_SEND_GROUPS,
|
||||
// STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet
|
||||
// STATE_SEND_OWNER, no need to send Owner specially, it is just part of the nodedb
|
||||
STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
|
||||
@@ -45,7 +46,7 @@ class PhoneAPI
|
||||
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
|
||||
const NodeInfo *nodeInfoForPhone = NULL;
|
||||
|
||||
ToRadio toRadioScratch; // this is a static scratch object, any data must be copied elsewhere before returning
|
||||
ToRadio toRadioScratch = {0}; // this is a static scratch object, any data must be copied elsewhere before returning
|
||||
|
||||
/// Use to ensure that clients don't get confused about old messages from the radio
|
||||
uint32_t config_nonce = 0;
|
||||
@@ -58,7 +59,7 @@ class PhoneAPI
|
||||
|
||||
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
|
||||
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
|
||||
virtual void close();
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Handle a ToRadio protobuf
|
||||
@@ -86,7 +87,7 @@ class PhoneAPI
|
||||
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
FromRadio fromRadioScratch;
|
||||
FromRadio fromRadioScratch = {};
|
||||
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
@@ -123,5 +124,5 @@ class PhoneAPI
|
||||
bool handleToRadioPacket(MeshPacket &p);
|
||||
|
||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||
virtual int onNotify(uint32_t newValue);
|
||||
virtual int onNotify(uint32_t newValue) override;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
template <class T> class PointerQueue : public TypedQueue<T *>
|
||||
{
|
||||
public:
|
||||
PointerQueue(int maxElements) : TypedQueue<T *>(maxElements) {}
|
||||
explicit PointerQueue(int maxElements) : TypedQueue<T *>(maxElements) {}
|
||||
|
||||
// returns a ptr or null if the queue was empty
|
||||
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY)
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
#include "SinglePortPlugin.h"
|
||||
|
||||
/**
|
||||
* A base class for mesh plugins that assume that they are sending/receiving one particular protobuf based
|
||||
* A base class for mesh modules that assume that they are sending/receiving one particular protobuf based
|
||||
* payload. Using one particular app ID.
|
||||
*
|
||||
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your plugin
|
||||
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your module
|
||||
* and avoid a bunch of boilerplate code.
|
||||
*/
|
||||
template <class T> class ProtobufPlugin : protected SinglePortPlugin
|
||||
@@ -51,7 +51,7 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp)
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) override
|
||||
{
|
||||
// FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us
|
||||
// it would be better to update even if the message was destined to others.
|
||||
@@ -67,7 +67,7 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
|
||||
decoded = &scratch;
|
||||
else
|
||||
DEBUG_MSG("Error decoding protobuf plugin!\n");
|
||||
DEBUG_MSG("Error decoding protobuf module!\n");
|
||||
}
|
||||
|
||||
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;
|
||||
|
||||
@@ -140,6 +140,8 @@ bool RF95Interface::reconfigure()
|
||||
void RF95Interface::addReceiveMetadata(MeshPacket *mp)
|
||||
{
|
||||
mp->rx_snr = lora->getSNR();
|
||||
mp->rx_rssi = lround(lora->getRSSI());
|
||||
|
||||
}
|
||||
|
||||
void RF95Interface::setStandby()
|
||||
|
||||
@@ -9,31 +9,31 @@
|
||||
*/
|
||||
class RF95Interface : public RadioLibInterface
|
||||
{
|
||||
RadioLibRF95 *lora; // Either a RFM95 or RFM96 depending on what was stuffed on this board
|
||||
RadioLibRF95 *lora = NULL; // Either a RFM95 or RFM96 depending on what was stuffed on this board
|
||||
|
||||
public:
|
||||
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
|
||||
|
||||
bool isIRQPending() { return lora->getPendingIRQ(); }
|
||||
bool isIRQPending() override { return lora->getPendingIRQ(); }
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool init();
|
||||
virtual bool init() override;
|
||||
|
||||
/// Apply any radio provisioning changes
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool reconfigure();
|
||||
virtual bool reconfigure() override;
|
||||
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep();
|
||||
virtual bool sleep() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Glue functions called from ISR land
|
||||
*/
|
||||
virtual void disableInterrupt();
|
||||
virtual void disableInterrupt() override;
|
||||
|
||||
/**
|
||||
* Enable a particular ISR callback glue function
|
||||
@@ -41,26 +41,26 @@ class RF95Interface : public RadioLibInterface
|
||||
virtual void enableInterrupt(void (*callback)()) { lora->setDio0Action(callback); }
|
||||
|
||||
/** are we actively receiving a packet (only called during receiving state) */
|
||||
virtual bool isActivelyReceiving();
|
||||
virtual bool isActivelyReceiving() override;
|
||||
|
||||
/**
|
||||
* Start waiting to receive a message
|
||||
*/
|
||||
virtual void startReceive();
|
||||
virtual void startReceive() override;
|
||||
|
||||
/**
|
||||
* Add SNR data to received messages
|
||||
*/
|
||||
virtual void addReceiveMetadata(MeshPacket *mp);
|
||||
virtual void addReceiveMetadata(MeshPacket *mp) override;
|
||||
|
||||
virtual void setStandby();
|
||||
virtual void setStandby() override;
|
||||
|
||||
/**
|
||||
* We override to turn on transmitter power as needed.
|
||||
*/
|
||||
virtual void configHardwareForSend();
|
||||
virtual void configHardwareForSend() override;
|
||||
|
||||
private:
|
||||
/** Some boards require GPIO control of tx vs rx paths */
|
||||
void setTransmitEnable(bool txon);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "configuration.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshRadio.h"
|
||||
@@ -6,45 +5,95 @@
|
||||
#include "NodeDB.h"
|
||||
#include "Router.h"
|
||||
#include "assert.h"
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
|
||||
#define RDEF(name, freq, spacing, num_ch, power_limit) \
|
||||
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \
|
||||
{ \
|
||||
RegionCode_##name, num_ch, power_limit, freq, spacing, #name \
|
||||
RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, #name \
|
||||
}
|
||||
|
||||
const RegionInfo regions[] = {
|
||||
RDEF(US, 903.08f, 2.16f, 13, 0), RDEF(EU433, 433.175f, 0.2f, 8, 0), RDEF(EU865, 865.2f, 0.3f, 10, 0),
|
||||
RDEF(CN, 470.0f, 2.0f, 20, 0),
|
||||
RDEF(JP, 920.0f, 0.5f, 10, 13), // See https://github.com/meshtastic/Meshtastic-device/issues/346 power level 13
|
||||
RDEF(ANZ, 916.0f, 0.5f, 20, 0), // AU/NZ channel settings 915-928MHz
|
||||
RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel
|
||||
// freq. (921.9f is for download, others are for uplink)
|
||||
RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz)
|
||||
RDEF(RU, 868.9f, 0.2f, 2, 20), // See notes below
|
||||
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
|
||||
/*
|
||||
https://link.springer.com/content/pdf/bbm%3A978-1-4842-4357-2%2F1.pdf
|
||||
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
|
||||
*/
|
||||
RDEF(US, 902.0f, 928.0f, 100, 0, 30, true, false),
|
||||
|
||||
/*
|
||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||
*/
|
||||
RDEF(EU433, 433.0f, 434.0f, 10, 0, 12, true, false),
|
||||
|
||||
/*
|
||||
https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/
|
||||
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
|
||||
https://www.legislation.gov.uk/uksi/1999/930/schedule/6/part/III/made/data.xht?view=snippet&wrap=true
|
||||
|
||||
audio_permitted = false per regulation
|
||||
*/
|
||||
RDEF(EU868, 869.4f, 869.65f, 10, 0, 16, false, false),
|
||||
|
||||
/*
|
||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||
*/
|
||||
RDEF(CN, 470.0f, 510.0f, 100, 0, 19, true, false),
|
||||
|
||||
/*
|
||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||
*/
|
||||
RDEF(JP, 920.8f, 927.8f, 100, 0, 16, true, false),
|
||||
|
||||
/*
|
||||
https://www.iot.org.au/wp/wp-content/uploads/2016/12/IoTSpectrumFactSheet.pdf
|
||||
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
|
||||
*/
|
||||
RDEF(ANZ, 915.0f, 928.0f, 100, 0, 30, true, false),
|
||||
|
||||
/*
|
||||
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf
|
||||
|
||||
Note:
|
||||
- We do LBT, so 100% is allowed.
|
||||
*/
|
||||
RDEF(RU, 868.7f, 869.2f, 100, 0, 20, true, false),
|
||||
|
||||
/*
|
||||
???
|
||||
*/
|
||||
RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false),
|
||||
|
||||
/*
|
||||
???
|
||||
*/
|
||||
RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false),
|
||||
|
||||
/*
|
||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||
*/
|
||||
RDEF(IN, 865.0f, 867.0f, 100, 0, 30, true, false),
|
||||
|
||||
/*
|
||||
https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752
|
||||
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
|
||||
*/
|
||||
RDEF(NZ865, 864.0f, 868.0f, 100, 0, 0, true, false),
|
||||
|
||||
/*
|
||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||
*/
|
||||
RDEF(TH, 920.0f, 925.0f, 100, 0, 16, true, false),
|
||||
|
||||
/*
|
||||
This needs to be last. Same as US.
|
||||
*/
|
||||
RDEF(Unset, 902.0f, 928.0f, 100, 0, 30, true, false)
|
||||
|
||||
};
|
||||
|
||||
/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2):
|
||||
|
||||
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018)
|
||||
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1 We have 3 options for 868 MHz:
|
||||
|
||||
864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports.
|
||||
866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports
|
||||
868,7 - 869,2 MHz ERP 100mW, Duty Cycle 10% or LBT, no resctrictions
|
||||
and according to RP2-1.0.2 LoRaWAN® Regional Parameters RP2-1.0.2 LoRaWAN® Regional Parameters - LoRa Alliance®
|
||||
I propose to use following meshtastic bandplan:
|
||||
1 channel - central frequency 868.9MHz 125kHz band
|
||||
Protective band - 75kHz
|
||||
2 channel - central frequency 869.1MHz 125kHz band
|
||||
|
||||
RDEF(RU, 868.9f, 0.2f, 2, 20)
|
||||
*/
|
||||
|
||||
const RegionInfo *myRegion;
|
||||
|
||||
void initRegion()
|
||||
@@ -54,8 +103,6 @@ void initRegion()
|
||||
;
|
||||
myRegion = r;
|
||||
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
|
||||
|
||||
myNodeInfo.num_bands = myRegion->numChannels; // Tell our android app how many channels we have
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,6 +219,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
if (p->rx_snr != 0.0) {
|
||||
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
|
||||
}
|
||||
if (p->rx_rssi != 0) {
|
||||
DEBUG_MSG(" rxSNR=%g", p->rx_rssi);
|
||||
}
|
||||
if (p->priority != 0)
|
||||
DEBUG_MSG(" priority=%d", p->priority);
|
||||
|
||||
@@ -274,38 +324,40 @@ void RadioInterface::applyModemConfig()
|
||||
auto channelSettings = channels.getPrimary();
|
||||
if (channelSettings.spread_factor == 0) {
|
||||
switch (channelSettings.modem_config) {
|
||||
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
|
||||
///< range
|
||||
bw = 125;
|
||||
cr = 5;
|
||||
case ChannelSettings_ModemConfig_ShortFast:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 7;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
|
||||
///< range
|
||||
bw = 500;
|
||||
cr = 5;
|
||||
sf = 7;
|
||||
case ChannelSettings_ModemConfig_ShortSlow:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 8;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
|
||||
///< range
|
||||
bw = 31.25;
|
||||
case ChannelSettings_ModemConfig_MidFast:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 9;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||
case ChannelSettings_ModemConfig_MidSlow:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 10;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_LongFast:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 11;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_LongSlow:
|
||||
bw = 125;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
|
||||
bw = 250;
|
||||
cr = 6;
|
||||
sf = 11;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
|
||||
bw = 250;
|
||||
cr = 7;
|
||||
sf = 10;
|
||||
case ChannelSettings_ModemConfig_VLongSlow:
|
||||
bw = 31.25;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
default:
|
||||
assert(0); // Unknown enum
|
||||
@@ -322,25 +374,26 @@ void RadioInterface::applyModemConfig()
|
||||
}
|
||||
|
||||
power = channelSettings.tx_power;
|
||||
|
||||
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
|
||||
|
||||
assert(myRegion); // Should have been found in init
|
||||
|
||||
// Calculate the number of channels
|
||||
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
|
||||
|
||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
||||
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels;
|
||||
float freq = myRegion->freq + radioConfig.preferences.frequency_offset + myRegion->spacing * channel_num;
|
||||
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % numChannels;
|
||||
float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
|
||||
|
||||
saveChannelNum(channel_num);
|
||||
saveFreq(freq);
|
||||
|
||||
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
|
||||
DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
|
||||
DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
|
||||
DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd,
|
||||
myRegion->freqEnd - myRegion->freqStart);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels);
|
||||
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", getFreq()); // the frequency could be overridden in RadioInterface::getFreq() for some modules
|
||||
DEBUG_MSG("Radio frequency: %f\n", getFreq());
|
||||
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
|
||||
}
|
||||
|
||||
@@ -404,4 +457,4 @@ size_t RadioInterface::beginSending(MeshPacket *p)
|
||||
|
||||
sendingPacket = p;
|
||||
return p->encrypted.size + sizeof(PacketHeader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,8 +205,8 @@ class RadioInterface
|
||||
class SimRadio : public RadioInterface
|
||||
{
|
||||
public:
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
virtual ErrorCode send(MeshPacket *p) override;
|
||||
};
|
||||
|
||||
/// Debug printing for packets
|
||||
void printPacket(const char *prefix, const MeshPacket *p);
|
||||
void printPacket(const char *prefix, const MeshPacket *p);
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
#include "RadioInterface.h"
|
||||
#include "MeshPacketQueue.h"
|
||||
|
||||
#ifdef CubeCell_BoardPlus
|
||||
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
|
||||
#endif
|
||||
|
||||
#define RADIOLIB_EXCLUDE_HTTP
|
||||
#include <RadioLib.h>
|
||||
|
||||
@@ -58,7 +54,7 @@ class LockingModule : public Module
|
||||
|
||||
\param numBytes Number of bytes to transfer.
|
||||
*/
|
||||
virtual void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes);
|
||||
virtual void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes) override;
|
||||
};
|
||||
|
||||
class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread
|
||||
@@ -99,7 +95,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
PhysicalLayer *iface;
|
||||
|
||||
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
|
||||
bool isReceiving;
|
||||
bool isReceiving = false;
|
||||
|
||||
public:
|
||||
/** Our ISR code currently needs this to find our active instance
|
||||
@@ -120,14 +116,14 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi,
|
||||
PhysicalLayer *iface = NULL);
|
||||
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
virtual ErrorCode send(MeshPacket *p) override;
|
||||
|
||||
/**
|
||||
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
|
||||
*
|
||||
* This method must be used before putting the CPU into deep or light sleep.
|
||||
*/
|
||||
virtual bool canSleep();
|
||||
virtual bool canSleep() override;
|
||||
|
||||
/**
|
||||
* Start waiting to receive a message
|
||||
@@ -142,7 +138,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
virtual bool isActivelyReceiving() = 0;
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id);
|
||||
virtual bool cancelSending(NodeNum from, PacketId id) override;
|
||||
|
||||
private:
|
||||
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
|
||||
@@ -157,7 +153,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
|
||||
static void timerCallback(void *p1, uint32_t p2);
|
||||
|
||||
virtual void onNotify(uint32_t notification);
|
||||
virtual void onNotify(uint32_t notification) override;
|
||||
|
||||
/** start an immediate transmit
|
||||
* This method is virtual so subclasses can hook as needed, subclasses should not call directly
|
||||
@@ -187,4 +183,4 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
virtual void addReceiveMetadata(MeshPacket *mp) = 0;
|
||||
|
||||
virtual void setStandby() = 0;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ class RadioLibRF95: public SX1278 {
|
||||
|
||||
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
|
||||
*/
|
||||
RadioLibRF95(Module* mod);
|
||||
explicit RadioLibRF95(Module* mod);
|
||||
|
||||
// basic methods
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ struct GlobalPacketId {
|
||||
|
||||
bool operator==(const GlobalPacketId &p) const { return node == p.node && id == p.id; }
|
||||
|
||||
GlobalPacketId(const MeshPacket *p)
|
||||
explicit GlobalPacketId(const MeshPacket *p)
|
||||
{
|
||||
node = getFrom(p);
|
||||
id = p->id;
|
||||
@@ -33,10 +33,10 @@ struct PendingPacket {
|
||||
MeshPacket *packet;
|
||||
|
||||
/** The next time we should try to retransmit this packet */
|
||||
uint32_t nextTxMsec;
|
||||
uint32_t nextTxMsec = 0;
|
||||
|
||||
/** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */
|
||||
uint8_t numRetransmissions;
|
||||
uint8_t numRetransmissions = 0;
|
||||
|
||||
/** True if we have started trying to find a route - for DSR usage
|
||||
* While trying to find a route we don't actually send the data packet. We just leave it here pending until
|
||||
@@ -45,7 +45,7 @@ struct PendingPacket {
|
||||
bool wantRoute = false;
|
||||
|
||||
PendingPacket() {}
|
||||
PendingPacket(MeshPacket *p);
|
||||
explicit PendingPacket(MeshPacket *p);
|
||||
};
|
||||
|
||||
class GlobalPacketIdHashFunction
|
||||
@@ -74,10 +74,10 @@ class ReliableRouter : public FloodingRouter
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
* If the txmit queue is full it might return an error
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
virtual ErrorCode send(MeshPacket *p) override;
|
||||
|
||||
/** Do our retransmission handling */
|
||||
virtual int32_t runOnce()
|
||||
virtual int32_t runOnce() override
|
||||
{
|
||||
// Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation
|
||||
auto d = doRetransmissions();
|
||||
@@ -91,7 +91,7 @@ class ReliableRouter : public FloodingRouter
|
||||
/**
|
||||
* Look for acks/naks or someone retransmitting us
|
||||
*/
|
||||
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
|
||||
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
|
||||
|
||||
/**
|
||||
* Try to find the pending packet record for this ID (or NULL if not found)
|
||||
@@ -102,7 +102,7 @@ class ReliableRouter : public FloodingRouter
|
||||
/**
|
||||
* We hook this method so we can see packets before FloodingRouter says they should be discarded
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p);
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) override;
|
||||
|
||||
/**
|
||||
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "RTC.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
#include "modules/RoutingModule.h"
|
||||
|
||||
#if defined(HAS_WIFI) || defined(PORTDUINO)
|
||||
#include "mqtt/MQTT.h"
|
||||
@@ -132,7 +132,7 @@ MeshPacket *Router::allocForSending()
|
||||
*/
|
||||
void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
{
|
||||
routingPlugin->sendAckNak(err, to, idFrom, chIndex);
|
||||
routingModule->sendAckNak(err, to, idFrom, chIndex);
|
||||
}
|
||||
|
||||
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
||||
@@ -210,6 +210,33 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
|
||||
|
||||
|
||||
|
||||
#if defined(HAS_WIFI) || defined(PORTDUINO)
|
||||
//check if we should send decrypted packets to mqtt
|
||||
|
||||
//truth table:
|
||||
/* mqtt_server mqtt_encryption_enabled should_encrypt
|
||||
* not set 0 1
|
||||
* not set 1 1
|
||||
* set 0 0
|
||||
* set 1 1
|
||||
*
|
||||
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
|
||||
*/
|
||||
|
||||
bool shouldActuallyEncrypt = true;
|
||||
if (*radioConfig.preferences.mqtt_server && !radioConfig.preferences.mqtt_encryption_enabled) {
|
||||
shouldActuallyEncrypt = false;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
|
||||
|
||||
//the packet is currently in a decrypted state. send it now if they want decrypted packets
|
||||
if (mqtt && !shouldActuallyEncrypt)
|
||||
mqtt->onSend(*p, chIndex);
|
||||
#endif
|
||||
|
||||
auto encodeResult = perhapsEncode(p);
|
||||
if (encodeResult != Routing_Error_NONE) {
|
||||
abortSendAndNak(encodeResult, p);
|
||||
@@ -217,7 +244,9 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
}
|
||||
|
||||
#if defined(HAS_WIFI) || defined(PORTDUINO)
|
||||
if (mqtt)
|
||||
//the packet is now encrypted.
|
||||
//check if we should send encrypted packets to mqtt
|
||||
if (mqtt && shouldActuallyEncrypt)
|
||||
mqtt->onSend(*p, chIndex);
|
||||
#endif
|
||||
}
|
||||
@@ -347,7 +376,7 @@ void Router::handleReceived(MeshPacket *p, RxSource src)
|
||||
printPacket("packet decoding failed (no PSK?)", p);
|
||||
}
|
||||
|
||||
// call plugins here
|
||||
// call modules here
|
||||
MeshPlugin::callPlugins(*p, src);
|
||||
}
|
||||
|
||||
@@ -368,4 +397,4 @@ void Router::perhapsHandleReceived(MeshPacket *p)
|
||||
handleReceived(p);
|
||||
|
||||
packetPool.release(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class Router : protected concurrency::OSThread
|
||||
* do idle processing
|
||||
* Mostly looking in our incoming rxPacket queue and calling handleReceived.
|
||||
*/
|
||||
virtual int32_t runOnce();
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
/**
|
||||
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue.
|
||||
@@ -71,7 +71,7 @@ class Router : protected concurrency::OSThread
|
||||
void enqueueReceivedMessage(MeshPacket *p);
|
||||
|
||||
protected:
|
||||
friend class RoutingPlugin;
|
||||
friend class RoutingModule;
|
||||
|
||||
/**
|
||||
* Send a packet on a suitable interface. This routine will
|
||||
@@ -85,7 +85,7 @@ class Router : protected concurrency::OSThread
|
||||
/**
|
||||
* Should this incoming filter be dropped?
|
||||
*
|
||||
* FIXME, move this into the new RoutingPlugin and do the filtering there using the regular plugin logic
|
||||
* FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic
|
||||
*
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
@@ -143,4 +143,4 @@ extern Router *router;
|
||||
|
||||
/// Generate a unique packet id
|
||||
// FIXME, move this someplace better
|
||||
PacketId generatePacketId();
|
||||
PacketId generatePacketId();
|
||||
|
||||
@@ -9,7 +9,7 @@ class SX1268Interface : public SX126xInterface<SX1268>
|
||||
{
|
||||
public:
|
||||
/// override frequency of the SX1268 module regardless of the region (use EU433 value)
|
||||
virtual float getFreq() { return 433.175f; }
|
||||
virtual float getFreq() override { return 433.175f; }
|
||||
|
||||
SX1268Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
|
||||
};
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user