mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-07 18:37:52 +00:00
Compare commits
223 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75281e8c97 | ||
|
|
8d47e4f3e0 | ||
|
|
92124e1224 | ||
|
|
c798c0032c | ||
|
|
2c5ea03b74 | ||
|
|
9d452ebf29 | ||
|
|
8a20155214 | ||
|
|
6a872b6ac2 | ||
|
|
52d61acc23 | ||
|
|
2594ea0c2c | ||
|
|
9623be1484 | ||
|
|
d810ce0c1e | ||
|
|
efd39c0f49 | ||
|
|
5f45a10db5 | ||
|
|
5f948c09fe | ||
|
|
22f3efd083 | ||
|
|
88716fc352 | ||
|
|
5c1d8b5bb0 | ||
|
|
b68397a911 | ||
|
|
5fdcb72d46 | ||
|
|
b70a359fe8 | ||
|
|
a9c8564524 | ||
|
|
b527e0d447 | ||
|
|
d8669f860a | ||
|
|
78f104c6de | ||
|
|
2f8e663f03 | ||
|
|
7f7b07ce9d | ||
|
|
cdb4756d9d | ||
|
|
385e291f51 | ||
|
|
7e60078791 | ||
|
|
073eecd147 | ||
|
|
525fe9b96c | ||
|
|
c7f411fc7c | ||
|
|
fc96500329 | ||
|
|
4e87c4411c | ||
|
|
9eb9c473db | ||
|
|
bfd147062f | ||
|
|
890ec7bdb2 | ||
|
|
76269b397f | ||
|
|
9fb6b1718f | ||
|
|
57c82988e2 | ||
|
|
1e3b037fea | ||
|
|
1e7808991d | ||
|
|
4f4cdf4f9e | ||
|
|
78f2c656d0 | ||
|
|
37ec969f96 | ||
|
|
f1a6693bb7 | ||
|
|
8ffd5a1d4f | ||
|
|
29eb5e8327 | ||
|
|
c175c21189 | ||
|
|
fc2862bd16 | ||
|
|
c9f814a9a7 | ||
|
|
92d2d3960b | ||
|
|
7872cb050d | ||
|
|
89029311c1 | ||
|
|
f6f586decb | ||
|
|
471c06b169 | ||
|
|
040bb1d1e0 | ||
|
|
bbaf5946f0 | ||
|
|
5286f23c9a | ||
|
|
7e9e33d462 | ||
|
|
04225f7bc2 | ||
|
|
dd0f1b2704 | ||
|
|
669807524e | ||
|
|
97a5405293 | ||
|
|
f298c7d053 | ||
|
|
a59f5344de | ||
|
|
13cfce48fa | ||
|
|
0261c243e0 | ||
|
|
ab325d6d2c | ||
|
|
b20930c111 | ||
|
|
770788d0a4 | ||
|
|
d02f615cad | ||
|
|
e17fe7e075 | ||
|
|
286686137f | ||
|
|
77c1112fe8 | ||
|
|
2d4ba357f7 | ||
|
|
455d0f8d66 | ||
|
|
5b0e7c6e82 | ||
|
|
78c665abb9 | ||
|
|
9a86d52d00 | ||
|
|
c5973f9a55 | ||
|
|
eb684aac03 | ||
|
|
7b4f8fb6d6 | ||
|
|
8065dbb2b7 | ||
|
|
049e791382 | ||
|
|
4fb8552563 | ||
|
|
90576f44d8 | ||
|
|
9e0a2964a4 | ||
|
|
49b16fdf0c | ||
|
|
1fcec8ce3b | ||
|
|
d32386a027 | ||
|
|
9b57d28c7d | ||
|
|
b9fd726c14 | ||
|
|
f165418b18 | ||
|
|
e193f63687 | ||
|
|
1eb37dded8 | ||
|
|
13889124c1 | ||
|
|
9005aaa14e | ||
|
|
df4e325e43 | ||
|
|
4ebc07b691 | ||
|
|
79a8d023ca | ||
|
|
330d83e7c3 | ||
|
|
a74384f3f5 | ||
|
|
da732c291f | ||
|
|
648d9dd19f | ||
|
|
e9faf657df | ||
|
|
103ffde025 | ||
|
|
baeb002245 | ||
|
|
0ce7a3f0ec | ||
|
|
0befad82a7 | ||
|
|
b357d8ae5b | ||
|
|
dd9beff9a5 | ||
|
|
d652664126 | ||
|
|
4666c12547 | ||
|
|
2b74260e2b | ||
|
|
620d336e55 | ||
|
|
e845a3388b | ||
|
|
a25235dc03 | ||
|
|
d3cbc8ea78 | ||
|
|
b6e197371d | ||
|
|
5cc3ff16a3 | ||
|
|
d93d5d2e37 | ||
|
|
7491af8ad7 | ||
|
|
fce95431e6 | ||
|
|
591a07c0fe | ||
|
|
c410f2d151 | ||
|
|
9502fa62e6 | ||
|
|
2a6480ec48 | ||
|
|
7c5ab885be | ||
|
|
21cfb151a8 | ||
|
|
84505b1717 | ||
|
|
d735e3006e | ||
|
|
af5d82dbde | ||
|
|
a97072eca0 | ||
|
|
cef6e248e7 | ||
|
|
b4c379f5fc | ||
|
|
3bb1206b9c | ||
|
|
002532401d | ||
|
|
8957c5892f | ||
|
|
1b8f41d353 | ||
|
|
0c51cc3738 | ||
|
|
2b9a8f0822 | ||
|
|
ddcfff3b59 | ||
|
|
449a3959b0 | ||
|
|
719a0c485b | ||
|
|
a4bbdc443f | ||
|
|
999afdf05e | ||
|
|
f492f6deb6 | ||
|
|
60f7ec8998 | ||
|
|
469d0ade72 | ||
|
|
1f33b03c30 | ||
|
|
351be2f327 | ||
|
|
3f401e8cac | ||
|
|
b20b21c553 | ||
|
|
c62863b1dc | ||
|
|
8505a0f260 | ||
|
|
98d878cdfe | ||
|
|
6730731652 | ||
|
|
27c35f69aa | ||
|
|
53671283ae | ||
|
|
d9fc7b32c3 | ||
|
|
9a03536e3d | ||
|
|
efebb8bb0b | ||
|
|
3bd1ae0be4 | ||
|
|
a07291d904 | ||
|
|
c0ac457cad | ||
|
|
6813a31895 | ||
|
|
8f5251583f | ||
|
|
c2122a6859 | ||
|
|
6dd65adebd | ||
|
|
c227143b53 | ||
|
|
cdd696c1ff | ||
|
|
3e6817cd18 | ||
|
|
a5ed607261 | ||
|
|
7118200885 | ||
|
|
b7f9064f0d | ||
|
|
5dc5bce1b2 | ||
|
|
bc7fef1d1a | ||
|
|
1908d131ca | ||
|
|
8cd2a00a25 | ||
|
|
c097852ab0 | ||
|
|
b02212009a | ||
|
|
9d1971f0fa | ||
|
|
2d6261703a | ||
|
|
a97c2ae6eb | ||
|
|
76e2c39c63 | ||
|
|
ab9fe42f58 | ||
|
|
9d78ce6193 | ||
|
|
959b540c02 | ||
|
|
68781492ad | ||
|
|
590e147186 | ||
|
|
0b358674ff | ||
|
|
0df01f2586 | ||
|
|
ca23665463 | ||
|
|
f55ac8e9c9 | ||
|
|
6e37fe6343 | ||
|
|
217bd934d7 | ||
|
|
58715f454c | ||
|
|
772f2a15ff | ||
|
|
5b0d8381b9 | ||
|
|
d841d86bbc | ||
|
|
ecaae87b79 | ||
|
|
5835abbcf6 | ||
|
|
2f7c2a2aea | ||
|
|
87ec7b09aa | ||
|
|
f8ec072093 | ||
|
|
781d2f0ad6 | ||
|
|
7bbd2c0e80 | ||
|
|
77bac11d82 | ||
|
|
315cfe4f2d | ||
|
|
707ed75138 | ||
|
|
c0e180759d | ||
|
|
6ceb423033 | ||
|
|
ee961d01ed | ||
|
|
a3343bc1af | ||
|
|
ee04d57a7f | ||
|
|
2cf704abe0 | ||
|
|
ef32ac5cd4 | ||
|
|
52d85c9a41 | ||
|
|
da03490310 | ||
|
|
aedca25fa8 | ||
|
|
c25efac0c1 |
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -7,7 +7,7 @@
|
|||||||
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
|
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
|
||||||
- Please do not check in files that don't have real changes
|
- Please do not check in files that don't have real changes
|
||||||
- Please do not reformat lines that you didn't have to change the code on
|
- Please do not reformat lines that you didn't have to change the code on
|
||||||
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor,
|
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor and the 'clang-format' extension,
|
||||||
because automatically follows our indentation rules and it's auto reformatting will not cause spurious changes to lines.
|
because automatically follows our indentation rules and it's auto reformatting will not cause spurious changes to lines.
|
||||||
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
|
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
|
||||||
- If your other co-developers have comments on your PR please tweak as needed.
|
- If your other co-developers have comments on your PR please tweak as needed.
|
||||||
|
|||||||
27
.github/workflows/main.yml
vendored
27
.github/workflows/main.yml
vendored
@@ -7,28 +7,33 @@ jobs:
|
|||||||
setup:
|
setup:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- name: Checkout code
|
||||||
- name: Checkout submodules
|
uses: actions/checkout@v2
|
||||||
uses: textbook/git-checkout-submodule-action@master
|
with:
|
||||||
|
submodules: true
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@master
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
- name: Install Platform IO
|
- name: Install Platform IO and meshtastic-python
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -U platformio
|
pip install -U platformio meshtastic
|
||||||
- name: Install extra python tools
|
- name: Install extra python tools
|
||||||
run: |
|
run: |
|
||||||
pip install -U adafruit-nrfutil
|
pip install -U adafruit-nrfutil
|
||||||
- name: Install libs needed for linux build
|
|
||||||
run: |
|
|
||||||
sudo apt install -y libpsocksxx-dev
|
|
||||||
- name: Build for tbeam
|
- name: Build for tbeam
|
||||||
run: platformio run -e tbeam
|
run: platformio run -e tbeam
|
||||||
- name: Build for heltec
|
- name: Build for heltec
|
||||||
run: platformio run -e heltec
|
run: platformio run -e heltec
|
||||||
- name: Build for lora-relay-v1
|
- name: Build for lora-relay-v1
|
||||||
run: platformio run -e lora-relay-v1
|
run: platformio run -e lora-relay-v1
|
||||||
- name: Build for linux
|
- name: Build for native
|
||||||
run: platformio run -e linux
|
run: platformio run -e native
|
||||||
|
- name: Integration test
|
||||||
|
run: |
|
||||||
|
.pio/build/native/program &
|
||||||
|
sleep 5
|
||||||
|
echo "Simulator started, launching python test..."
|
||||||
|
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -15,7 +15,8 @@ Thumbs.db
|
|||||||
.built
|
.built
|
||||||
.context
|
.context
|
||||||
.cproject
|
.cproject
|
||||||
.idea/*
|
|
||||||
.vagrant
|
.vagrant
|
||||||
nanopb*
|
nanopb*
|
||||||
flash.uf2
|
flash.uf2
|
||||||
|
cmake-build*
|
||||||
|
|
||||||
|
|||||||
7
.idea/codeStyles/Project.xml
generated
Normal file
7
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<clangFormatSettings>
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</clangFormatSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
2
.idea/meshtastic-esp32.iml
generated
Normal file
2
.idea/meshtastic-esp32.iml
generated
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||||
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/meshtastic-esp32.iml" filepath="$PROJECT_DIR$/.idea/meshtastic-esp32.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
9
.idea/vcs.xml
generated
Normal file
9
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/design" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/proto" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/sdk-nrfxlib" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
143
.idea/workspace.xml
generated
Normal file
143
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeRunConfigurationManager" shouldGenerate="true" shouldDeleteObsolete="true">
|
||||||
|
<generated>
|
||||||
|
<config projectName="meshtastic-esp32" targetName="Debug" />
|
||||||
|
<config projectName="meshtastic-esp32" targetName="Production" />
|
||||||
|
<config projectName="meshtastic-esp32" targetName="Z_DUMMY_TARGET" />
|
||||||
|
</generated>
|
||||||
|
</component>
|
||||||
|
<component name="CMakeSettings">
|
||||||
|
<configurations>
|
||||||
|
<configuration PROFILE_NAME="native" CONFIG_NAME="native" ENABLED="true" />
|
||||||
|
</configurations>
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="58922733-b05b-4b90-9655-b9b18914977a" name="Default Changelist" comment="">
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/platformio.ini" beforeDir="false" afterPath="$PROJECT_DIR$/platformio.ini" afterDir="false" />
|
||||||
|
</list>
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectId" id="1pmWHw2wau2TbdKvXvmQUB0EUE9" />
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="ASKED_ADD_EXTERNAL_FILES" value="true" />
|
||||||
|
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||||
|
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
|
<property name="cf.advertisement.text.overridden" value="true" />
|
||||||
|
<property name="cf.first.check.clang-format" value="false" />
|
||||||
|
<property name="node.js.detected.package.eslint" value="true" />
|
||||||
|
<property name="node.js.detected.package.tslint" value="true" />
|
||||||
|
<property name="node.js.path.for.package.eslint" value="project" />
|
||||||
|
<property name="node.js.path.for.package.tslint" value="project" />
|
||||||
|
<property name="node.js.selected.package.eslint" value="(autodetect)" />
|
||||||
|
<property name="node.js.selected.package.tslint" value="(autodetect)" />
|
||||||
|
<property name="settings.editor.selected.configurable" value="CMakeSettings" />
|
||||||
|
</component>
|
||||||
|
<component name="RunManager" selected="GDB Remote Debug.gdbremote-localhost-2345">
|
||||||
|
<configuration default="true" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
|
||||||
|
<debugger kind="GDB" isBundled="true" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="gdbremote-localhost-2345" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
|
||||||
|
<debugger kind="GDB" isBundled="true" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="Z_DUMMY_TARGET" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Z_DUMMY_TARGET" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Z_DUMMY_TARGET">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<configuration name="PlatformIO Debug" type="platformio" factoryName="PlatformIO Debug" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Debug" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Debug">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<configuration name="PlatformIO Upload" type="platformio" factoryName="PlatformIO Upload" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Production" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Production">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<list>
|
||||||
|
<item itemvalue="CMake Application.Z_DUMMY_TARGET" />
|
||||||
|
<item itemvalue="GDB Remote Debug.gdbremote-localhost-2345" />
|
||||||
|
<item itemvalue="PlatformIO.PlatformIO Debug" />
|
||||||
|
<item itemvalue="PlatformIO.PlatformIO Upload" />
|
||||||
|
</list>
|
||||||
|
</component>
|
||||||
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="58922733-b05b-4b90-9655-b9b18914977a" name="Default Changelist" comment="" />
|
||||||
|
<created>1615788661896</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1615788661896</updated>
|
||||||
|
<workItem from="1615788663210" duration="6661000" />
|
||||||
|
<workItem from="1615938346019" duration="1208000" />
|
||||||
|
<workItem from="1615971126983" duration="5945000" />
|
||||||
|
<workItem from="1617115374907" duration="357000" />
|
||||||
|
<workItem from="1617115747078" duration="1391000" />
|
||||||
|
<workItem from="1617117632667" duration="307000" />
|
||||||
|
<workItem from="1617160691713" duration="1016000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
<component name="Vcs.Log.Tabs.Properties">
|
||||||
|
<option name="TAB_STATES">
|
||||||
|
<map>
|
||||||
|
<entry key="MAIN">
|
||||||
|
<value>
|
||||||
|
<State />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="oldMeFiltersMigrated" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager>
|
||||||
|
<breakpoints>
|
||||||
|
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||||
|
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||||
|
<line>53</line>
|
||||||
|
<option name="timeStamp" value="6" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||||
|
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||||
|
<line>37</line>
|
||||||
|
<option name="timeStamp" value="7" />
|
||||||
|
</line-breakpoint>
|
||||||
|
</breakpoints>
|
||||||
|
</breakpoint-manager>
|
||||||
|
<watches-manager>
|
||||||
|
<configuration name="CLion_Remote">
|
||||||
|
<watch expression="radioConfig" language="ObjectiveC" />
|
||||||
|
</configuration>
|
||||||
|
</watches-manager>
|
||||||
|
</component>
|
||||||
|
<component name="XSLT-Support.FileAssociations.UIState">
|
||||||
|
<expand />
|
||||||
|
<select />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -2,6 +2,7 @@
|
|||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
// for the documentation about the extensions.json format
|
// for the documentation about the extensions.json format
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"platformio.platformio-ide"
|
"platformio.platformio-ide",
|
||||||
|
"xaver.clang-format"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -69,6 +69,7 @@
|
|||||||
"wifi"
|
"wifi"
|
||||||
],
|
],
|
||||||
"C_Cpp.dimInactiveRegions": true,
|
"C_Cpp.dimInactiveRegions": true,
|
||||||
|
"cmake.configureOnOpen": true,
|
||||||
"protoc": {
|
"protoc": {
|
||||||
"compile_on_save": false,
|
"compile_on_save": false,
|
||||||
"compile_all_path": "/home/kevinh/development/meshtastic/meshtastic-esp32/proto",
|
"compile_all_path": "/home/kevinh/development/meshtastic/meshtastic-esp32/proto",
|
||||||
@@ -76,5 +77,6 @@
|
|||||||
"--java_out=/tmp",
|
"--java_out=/tmp",
|
||||||
"-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto"
|
"-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"editor.formatOnSave": true
|
||||||
}
|
}
|
||||||
36
CMakeLists.txt
Normal file
36
CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
|
||||||
|
# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
|
||||||
|
#
|
||||||
|
# If you need to override existing CMake configuration or add extra,
|
||||||
|
# please create `CMakeListsUser.txt` in the root of project.
|
||||||
|
# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
set(CMAKE_SYSTEM_NAME Generic)
|
||||||
|
set(CMAKE_C_COMPILER_WORKS 1)
|
||||||
|
set(CMAKE_CXX_COMPILER_WORKS 1)
|
||||||
|
|
||||||
|
project("meshtastic-esp32" C CXX)
|
||||||
|
|
||||||
|
include(CMakeListsPrivate.txt)
|
||||||
|
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt)
|
||||||
|
include(CMakeListsUser.txt)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories("$ENV{HOME}/.platformio/packages/framework-portduino")
|
||||||
|
include_directories("/usr/include")
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
Production ALL
|
||||||
|
COMMAND platformio -c clion run "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
Debug ALL
|
||||||
|
COMMAND platformio -c clion run --target debug "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(Z_DUMMY_TARGET ${SRC_LIST})
|
||||||
2041
CMakeListsPrivate.txt
Normal file
2041
CMakeListsPrivate.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -199,7 +199,7 @@ We'd love to have you join us on this merry little project. Please see our [deve
|
|||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
This project is run by volunteers. Past contributors include:
|
This project is run by volunteers. We are a friendly group and welcome any contribution (code fixes, documentation, features, bug reports etc...). We try to be good about listing contributor names in release notes, but it has become unwieldy for the main-devs to keep updating the list below and we've neglected it too long. If you'd like your name included in this list please send a pull request to edit this README and simply add your line yourself. Thank you very much for your help!
|
||||||
|
|
||||||
- @astro-arphid: Added support for 433MHz radios in europe.
|
- @astro-arphid: Added support for 433MHz radios in europe.
|
||||||
- @claesg: Various documentation fixes and 3D print enclosures
|
- @claesg: Various documentation fixes and 3D print enclosures
|
||||||
|
|||||||
@@ -4,13 +4,7 @@ set -e
|
|||||||
|
|
||||||
VERSION=`bin/buildinfo.py`
|
VERSION=`bin/buildinfo.py`
|
||||||
|
|
||||||
# We now only do regionless builds
|
BOARDS_ESP32="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
|
||||||
COUNTRIES=""
|
|
||||||
#COUNTRIES="US EU433 EU865 CN JP ANZ KR"
|
|
||||||
#COUNTRIES=US
|
|
||||||
#COUNTRIES=CN
|
|
||||||
|
|
||||||
BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
|
|
||||||
#BOARDS_ESP32=tbeam
|
#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
|
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
|
||||||
@@ -30,26 +24,17 @@ mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal
|
|||||||
# build the named environment and copy the bins to the release directory
|
# build the named environment and copy the bins to the release directory
|
||||||
function do_build() {
|
function do_build() {
|
||||||
BOARD=$1
|
BOARD=$1
|
||||||
COUNTRY=$2
|
|
||||||
isNrf=$3
|
isNrf=$3
|
||||||
|
|
||||||
echo "Building $COUNTRY for $BOARD with $PLATFORMIO_BUILD_FLAGS"
|
echo "Building for $BOARD with $PLATFORMIO_BUILD_FLAGS"
|
||||||
rm -f .pio/build/$BOARD/firmware.*
|
rm -f .pio/build/$BOARD/firmware.*
|
||||||
|
|
||||||
# The shell vars the build tool expects to find
|
# The shell vars the build tool expects to find
|
||||||
export APP_VERSION=$VERSION
|
export APP_VERSION=$VERSION
|
||||||
|
|
||||||
# Are we building a universal/regionless rom?
|
# Are we building a universal/regionless rom?
|
||||||
if [ "x$COUNTRY" != "x" ]
|
export HW_VERSION="1.0"
|
||||||
then
|
basename=universal/firmware-$BOARD-$VERSION
|
||||||
export HW_VERSION="1.0-$COUNTRY"
|
|
||||||
export COUNTRY
|
|
||||||
basename=firmware-$BOARD-$COUNTRY-$VERSION
|
|
||||||
else
|
|
||||||
export HW_VERSION="1.0"
|
|
||||||
unset COUNTRY
|
|
||||||
basename=universal/firmware-$BOARD-$VERSION
|
|
||||||
fi
|
|
||||||
|
|
||||||
pio run --environment $BOARD # -v
|
pio run --environment $BOARD # -v
|
||||||
SRCELF=.pio/build/$BOARD/firmware.elf
|
SRCELF=.pio/build/$BOARD/firmware.elf
|
||||||
@@ -71,10 +56,6 @@ function do_boards() {
|
|||||||
declare boards=$1
|
declare boards=$1
|
||||||
declare isNrf=$2
|
declare isNrf=$2
|
||||||
for board in $boards; do
|
for board in $boards; do
|
||||||
for country in $COUNTRIES; do
|
|
||||||
do_build $board $country "$isNrf"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Build universal
|
# Build universal
|
||||||
do_build $board "" "$isNrf"
|
do_build $board "" "$isNrf"
|
||||||
done
|
done
|
||||||
|
|||||||
38
bin/build-nightly.sh
Executable file
38
bin/build-nightly.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
source ~/.bashrc
|
||||||
|
|
||||||
|
# Meshtastic Nightly Build Script.
|
||||||
|
# McHamster (jm@casler.org)
|
||||||
|
#
|
||||||
|
# This is the script that is used for the nightly build server.
|
||||||
|
#
|
||||||
|
# It's probably not useful for most people, but you may want to run your own
|
||||||
|
# nightly builds.
|
||||||
|
#
|
||||||
|
# The last line of ~/.bashrc contains an inclusion of platformio in the path.
|
||||||
|
# Without this, the build script won't run from the crontab:
|
||||||
|
#
|
||||||
|
# export PATH="$HOME/.platformio/penv/bin:$PATH"
|
||||||
|
#
|
||||||
|
# The crontab contains:
|
||||||
|
# 0 2 * * * cd ~/meshtastic/github/meshtastic && source "~/.bashrc"; ./build-nightly.sh > ~/cronout.txt 2> ~/cronout.txt
|
||||||
|
|
||||||
|
cd Meshtastic-device
|
||||||
|
|
||||||
|
git pull
|
||||||
|
|
||||||
|
bin/build-all.sh
|
||||||
|
|
||||||
|
date_stamp=$(date +'%Y-%m-%d')
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# TODO: Archive the same binaries used by the build-all script.
|
||||||
|
#zip -r meshtastic_device_nightly_${date_stamp} Meshtastic-device/release/latest/bins
|
||||||
|
cp Meshtastic-device/release/archive/`ls -t ./Meshtastic-device/release/archive/| head -1` meshtastic_device_nightly_${date_stamp}.zip
|
||||||
|
|
||||||
|
# Copy the file to the webserver
|
||||||
|
scp meshtastic_device_nightly_${date_stamp}.zip jm@10.11.12.20:/volume1/web/meshtastic/nightly_builds/
|
||||||
|
|
||||||
|
# Delete the local copy
|
||||||
|
rm meshtastic_device_nightly_${date_stamp}.zip
|
||||||
@@ -1,21 +1,24 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
PYTHON=${PYTHON:-python3}
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Usage info
|
# Usage info
|
||||||
show_help() {
|
show_help() {
|
||||||
cat << EOF
|
cat << EOF
|
||||||
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-f FILENAME]
|
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME]
|
||||||
Flash image file to device, but first erasing and writing system information"
|
Flash image file to device, but first erasing and writing system information"
|
||||||
|
|
||||||
-h Display this help and exit
|
-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 (Dangerrous).
|
||||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
-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
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while getopts ":h:p:f:" opt; do
|
while getopts ":hp:P:f:" opt; do
|
||||||
case "${opt}" in
|
case "${opt}" in
|
||||||
h)
|
h)
|
||||||
show_help
|
show_help
|
||||||
@@ -23,6 +26,8 @@ while getopts ":h:p:f:" opt; do
|
|||||||
;;
|
;;
|
||||||
p) export ESPTOOL_PORT=${OPTARG}
|
p) export ESPTOOL_PORT=${OPTARG}
|
||||||
;;
|
;;
|
||||||
|
P) PYTHON=${OPTARG}
|
||||||
|
;;
|
||||||
f) FILENAME=${OPTARG}
|
f) FILENAME=${OPTARG}
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -36,10 +41,10 @@ shift "$((OPTIND-1))"
|
|||||||
|
|
||||||
if [ -f "${FILENAME}" ]; then
|
if [ -f "${FILENAME}" ]; then
|
||||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||||
esptool.py --baud 921600 erase_flash
|
$PYTHON -m esptool --baud 921600 erase_flash
|
||||||
esptool.py --baud 921600 write_flash 0x1000 system-info.bin
|
$PYTHON -m esptool --baud 921600 write_flash 0x1000 system-info.bin
|
||||||
esptool.py --baud 921600 write_flash 0x00390000 spiffs-*.bin
|
$PYTHON -m esptool --baud 921600 write_flash 0x00390000 spiffs-*.bin
|
||||||
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
|
$PYTHON -m esptool --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||||
else
|
else
|
||||||
echo "Invalid file: ${FILENAME}"
|
echo "Invalid file: ${FILENAME}"
|
||||||
show_help
|
show_help
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
PYTHON=${PYTHON:-python3}
|
||||||
|
|
||||||
# Usage info
|
# Usage info
|
||||||
show_help() {
|
show_help() {
|
||||||
cat << EOF
|
cat << EOF
|
||||||
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] -f FILENAME
|
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-P PYTHON] -f FILENAME
|
||||||
Flash image file to device, leave existing system intact."
|
Flash image file to device, leave existing system intact."
|
||||||
|
|
||||||
-h Display this help and exit
|
-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 (Dangerrous).
|
||||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
-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
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while getopts ":h:p:f:" opt; do
|
while getopts ":hp:P:f:" opt; do
|
||||||
case "${opt}" in
|
case "${opt}" in
|
||||||
h)
|
h)
|
||||||
show_help
|
show_help
|
||||||
@@ -21,6 +24,8 @@ while getopts ":h:p:f:" opt; do
|
|||||||
;;
|
;;
|
||||||
p) export ESPTOOL_PORT=${OPTARG}
|
p) export ESPTOOL_PORT=${OPTARG}
|
||||||
;;
|
;;
|
||||||
|
P) PYTHON=${OPTARG}
|
||||||
|
;;
|
||||||
f) FILENAME=${OPTARG}
|
f) FILENAME=${OPTARG}
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -34,7 +39,9 @@ shift "$((OPTIND-1))"
|
|||||||
|
|
||||||
if [ -f "${FILENAME}" ]; then
|
if [ -f "${FILENAME}" ]; then
|
||||||
echo "Trying to flash update ${FILENAME}."
|
echo "Trying to flash update ${FILENAME}."
|
||||||
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
|
$PYTHON -m esptool --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||||
|
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
|
||||||
|
$PYTHON -m esptool --baud 921600 erase_region 0xe000 0x2000
|
||||||
else
|
else
|
||||||
echo "Invalid file: ${FILENAME}"
|
echo "Invalid file: ${FILENAME}"
|
||||||
show_help
|
show_help
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader
|
|||||||
|
|
||||||
nrfjprog --eraseall -f nrf52
|
nrfjprog --eraseall -f nrf52
|
||||||
|
|
||||||
|
# to get tool run "sudo apt-get install srecord"
|
||||||
|
|
||||||
# this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid
|
# this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid
|
||||||
# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000
|
# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000
|
||||||
# first 4 bytes should be 0x01 to indicate valid app image
|
# first 4 bytes should be 0x01 to indicate valid app image
|
||||||
@@ -14,7 +16,7 @@ echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin
|
|||||||
srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel
|
srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel
|
||||||
|
|
||||||
echo Generating merged hex file
|
echo Generating merged hex file
|
||||||
mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-125-gf38f8f4-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex
|
mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-213-gf67f592-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex
|
||||||
|
|
||||||
echo Telling bootloader app region is valid and telling CPU to run
|
echo Telling bootloader app region is valid and telling CPU to run
|
||||||
nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset
|
nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset
|
||||||
|
|||||||
3
bin/native-gdbserver.sh
Executable file
3
bin/native-gdbserver.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
set -e
|
||||||
|
pio run --environment native
|
||||||
|
gdbserver --once localhost:2345 .pio/build/native/program "$@"
|
||||||
3
bin/native-run.sh
Executable file
3
bin/native-run.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
set -e
|
||||||
|
pio run --environment native
|
||||||
|
.pio/build/native/program "$@"
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52840_XXAA
|
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52840_XXAA -SuppressInfoUpdateFW -DisableAutoUpdateFW -rtos GDBServer/RTOSPlugin_FreeRTOS
|
||||||
|
|||||||
3
bin/program-1.0-tbeam.sh
Executable file
3
bin/program-1.0-tbeam.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-EU865-1.0.0.bin
|
||||||
|
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
|
||||||
|
esptool.py --baud 921600 erase_region 0xe000 0x2000
|
||||||
1
bin/program-1.1-tbeam.sh
Executable file
1
bin/program-1.1-tbeam.sh
Executable file
@@ -0,0 +1 @@
|
|||||||
|
esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-1.1.50.bin
|
||||||
11
bin/run-both.sh
Executable file
11
bin/run-both.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
set -e
|
||||||
|
|
||||||
|
pio run
|
||||||
|
|
||||||
|
echo uploading to usb1
|
||||||
|
pio run --upload-port /dev/ttyUSB1 -t upload &
|
||||||
|
|
||||||
|
echo uploading to usb0
|
||||||
|
pio run --upload-port /dev/ttyUSB0 -t upload &
|
||||||
|
|
||||||
|
wait
|
||||||
48
boards/lora_isp4520.json
Normal file
48
boards/lora_isp4520.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52832_s132_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DNRF52832_XXAA -DNRF52",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"mcu": "nrf52832",
|
||||||
|
"variant": "lora_isp4520",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS132",
|
||||||
|
"sd_name": "s132",
|
||||||
|
"sd_version": "6.1.1",
|
||||||
|
"sd_fwid": "0x00B7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"bluetooth"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52832_xxAA",
|
||||||
|
"svd_path": "nrf52.svd"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino"
|
||||||
|
],
|
||||||
|
"name": "lora ISP4520",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 65536,
|
||||||
|
"maximum_size": 524288,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "nrfutil",
|
||||||
|
"protocols": [
|
||||||
|
"jlink",
|
||||||
|
"nrfjprog",
|
||||||
|
"nrfutil",
|
||||||
|
"stlink"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": "",
|
||||||
|
"vendor": "PsiSoft"
|
||||||
|
}
|
||||||
@@ -2,8 +2,72 @@
|
|||||||
|
|
||||||
You probably don't care about this section - skip to the next one.
|
You probably don't care about this section - skip to the next one.
|
||||||
|
|
||||||
## 1.2 cleanup & multichannel support:
|
## before next release
|
||||||
|
|
||||||
|
* fix heltec battery scaling
|
||||||
|
* DONE remote admin busted?
|
||||||
|
* DONE check android code - @havealoha comments about odd sleep behavior
|
||||||
|
* ABANDONED test github actions locally on linux
|
||||||
|
* DONE fix github actions per sasha tip
|
||||||
|
* tell ttgo to preinstall new bins
|
||||||
|
* DONE sendtext busted in portduino, due to bytetime calculations
|
||||||
|
* remove linux dependency in native build
|
||||||
|
* DONE tcp stream problem in python+pordtuino, server thinks client dropped when client DID NOT DROP
|
||||||
|
* DONE TCP mode for android, localhost is at 10.0.2.2
|
||||||
|
* make sure USB still works in android
|
||||||
|
* add portduino builds to zip
|
||||||
|
* add license to portduino and make announcement
|
||||||
|
* DONE naks are being dropped (though enqueuedLocal) sometimes before phone/PC gets them
|
||||||
|
* DONE have android fill in if local GPS has poor signal
|
||||||
|
* optionally restrict position sends to a named channel
|
||||||
|
* release to beta and amazon
|
||||||
|
* add reference counting to mesh packets
|
||||||
|
* allow multiple simultanteous phoneapi connections
|
||||||
|
* DONE split position.time and last_heard
|
||||||
|
* DONE update android app to use last_heard
|
||||||
|
* DONE turn off bluetooth interface ENTIRELY while using serial API (was python client times out on connect sometimes)
|
||||||
|
* DONE gps assistance from phone not working?
|
||||||
|
* DONE test latest firmware update with is_router
|
||||||
|
* DONE firmware OTA updates of is_router true nodes fails?
|
||||||
|
* DONE add UI in android app to reset to defaults https://github.com/meshtastic/Meshtastic-Android/issues/263
|
||||||
|
* DONE TEST THIS! changing channels requires a reboot to take effect https://github.com/meshtastic/Meshtastic-device/issues/752
|
||||||
|
* DONE bug report with remote info request timing out
|
||||||
|
* DONE retest channel changing in android (using sim?)
|
||||||
|
* DONE move remote admin doc from forum into git
|
||||||
|
* DONE check crashlytics
|
||||||
|
* DONE ask for a documentation czar
|
||||||
|
* DONE timestamps on oled screen are wrong - don't seem to be updating based on message rx (actually: this is expected behavior when no node on the mesh has GPS time)
|
||||||
|
* DONE add ch-del
|
||||||
|
* DONE channel hash suffixes are wrong on android
|
||||||
|
* DONE before next relase: test empty channel sets on android
|
||||||
|
* DONE channel sharing in android
|
||||||
|
* DONE test 1.0 firmware update on android
|
||||||
|
* DONE test 1.1 firmware update on android
|
||||||
|
* DONE test 1.2.10 firmware update on android
|
||||||
|
* DONE test link sharing on android
|
||||||
|
* FIXED? luxon bug report - seeing rx acks for nodes that are not on the network
|
||||||
|
* DONE release py
|
||||||
|
* DONE show GPS time only if we know what global time is
|
||||||
|
* DONE android should always provide time to nodes - so that it is easier for the mesh to learn the current time
|
||||||
|
|
||||||
|
## MQTT
|
||||||
|
|
||||||
|
* mqtt.meshtastic.org should have VERY basic auth at launch (to prevent abuse)
|
||||||
|
* use MQTT for simulator mesh network
|
||||||
|
* do initial development inside of portduino
|
||||||
|
* do as much possible on the device side (so we can eventually just have ESP32 talk directly to server)
|
||||||
|
* eventually add a MQTTPacket on the ToRadio & FromRadio links
|
||||||
|
|
||||||
|
## Multichannel support
|
||||||
|
|
||||||
|
* DONE cleanup the external notification and serial plugins
|
||||||
|
* 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
|
||||||
|
* DONE fix android to use new device types for firmware update
|
||||||
|
* 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 RouterPlugin 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 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 send a hint that can be used to select which channel to try and hash against with each message
|
||||||
@@ -33,23 +97,29 @@ You probably don't care about this section - skip to the next one.
|
|||||||
* 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 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 plugin 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 don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
|
||||||
* fix 1.1.50 android debug panel display
|
* DONE fix 1.1.50 android debug panel display
|
||||||
* DONE test android channel setting
|
* DONE test android channel setting
|
||||||
* DONE release to users
|
* DONE release to users
|
||||||
* DONE warn in android app about unset regions
|
* DONE warn in android app about unset regions
|
||||||
* DONE use set-channel from android
|
* DONE use set-channel from android
|
||||||
* DONE add gui in android app for setting region
|
* DONE add gui in android app for setting region
|
||||||
|
* DONE clean up python channel usage
|
||||||
|
* DONE use bindToChannel to limit admin access for remote nodes
|
||||||
|
* DONE move channels and radio config out of device settings
|
||||||
|
* DONE test remote info and remote settings changes
|
||||||
* make python tests more exhaustive
|
* make python tests more exhaustive
|
||||||
* pick default random admin key
|
* DONE pick default random admin key
|
||||||
* exclude admin channels from URL?
|
* exclude admin channels from URL?
|
||||||
* make a way to share just secondary channels via URL
|
* make a way to share just secondary channels via URL
|
||||||
* use single byte 'well known' channel names for the four default channel names (longslow etc), and for admin, gpio, etc...
|
* generalize the concept of "shortstrings" use it for both PSKs and well known channel names. Possibly use a ShortString class.
|
||||||
|
* use single byte 'well known' channel names for admin, gpio, etc...
|
||||||
* use presence of gpio channel to enable gpio ops, same for serial etc...
|
* use presence of gpio channel to enable gpio ops, same for serial etc...
|
||||||
* restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
|
* DONE restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
|
||||||
* add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
|
* DONE add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
|
||||||
* stress test multi channel
|
* stress test multi channel
|
||||||
* investigate @mc-hamster report of heap corruption
|
* DONE investigate @mc-hamster report of heap corruption
|
||||||
* DONE use set-user from android
|
* DONE use set-user from android
|
||||||
|
* untrusted users should not be allowed to provide bogus times (via position broadcasts) to the rest of the mesh. Invent a new lowest quality notion of UntrustedTime.
|
||||||
* use portuino TCP connection to debug with python API
|
* use portuino TCP connection to debug with python API
|
||||||
* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered)
|
* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered)
|
||||||
* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
|
* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
|
||||||
@@ -61,49 +131,34 @@ 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
|
* 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.
|
* 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
|
* 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
|
||||||
* confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
|
* DONE confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
|
||||||
* confirm we are still multi hop routing flood broadcasts
|
* DONE confirm we are still multi hop routing flood broadcasts
|
||||||
* confirm we are still doing resends on unicast reliable packets
|
* 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
|
* add history to routed packets: https://meshtastic.discourse.group/t/packet-source-tracking/2764/2
|
||||||
* add support for full DSR unicast delivery
|
* add support for full DSR unicast delivery
|
||||||
* DONE move acks into routing
|
* DONE move acks into routing
|
||||||
* DONE make all subpackets different versions of data
|
* DONE make all subpackets different versions of data
|
||||||
* DONE move routing control into a data packet
|
* 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 plugin (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)
|
||||||
* DONE figure out how to add micro_delta to position, make it so that phone apps don't need to understand it?
|
* DONE figure out how to add micro_delta to position, make it so that phone apps don't need to understand it?
|
||||||
* only send battery updates a max of once a minute
|
* only send battery updates a max of once a minute
|
||||||
* add python channel selection for sending
|
* DONE add python channel selection for sending
|
||||||
* DONE record recevied channel in meshpacket
|
* DONE record recevied channel in meshpacket
|
||||||
* test remote settings operations (confirm it works 3 hops away)
|
* test remote settings operations (confirm it works 3 hops away)
|
||||||
* DONE make a primaryChannel global and properly maintain it when the phone sends setChannel
|
* DONE make a primaryChannel global and properly maintain it when the phone sends setChannel
|
||||||
* DONE move setCrypto call into packet send and packet decode code
|
* DONE move setCrypto call into packet send and packet decode code
|
||||||
* implement 'small location diffs' change
|
* implement 'small location diffs' change
|
||||||
* move battery level out of position?
|
* move battery level out of position?
|
||||||
|
* consider "A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface
|
||||||
|
are allowed on any channel (this lets the local user do anything)." Probably by adding a "secure_local_interface" settings bool.
|
||||||
* DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads
|
* DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads
|
||||||
|
|
||||||
eink:
|
|
||||||
|
|
||||||
* new battery level sensing
|
|
||||||
* measure current draw
|
|
||||||
* DONE: fix backlight
|
|
||||||
* USB is busted because of power enable mode?
|
|
||||||
* OHH BME280! THAT IS GREAT!
|
|
||||||
* make new screen work, ask for datasheet
|
|
||||||
* say I think you could ship this
|
|
||||||
* leds seem busted
|
|
||||||
* usb doesn't stay connected
|
|
||||||
* check GPS works
|
|
||||||
* check GPS fast locking
|
|
||||||
* send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6
|
|
||||||
* send PR for bootloader
|
|
||||||
* fix nrf52 time/date
|
|
||||||
* send new master bin file
|
|
||||||
* send email about low power mode problems
|
|
||||||
* support new flash chip in appload, possibly use low power mode
|
|
||||||
* swbug! stuck busy tx occurred!
|
|
||||||
|
|
||||||
For app cleanup:
|
For app cleanup:
|
||||||
|
|
||||||
|
* don't store redundant User admin or position broadcasts in the ToPhone queue (only keep one per sending node per proto type, and only most recent)
|
||||||
* use structured logging to kep logs in ram. Also send logs as packets to api clients
|
* use structured logging to kep logs in ram. Also send logs as packets to api clients
|
||||||
* DONE writeup nice python options docs (common cases, link to protobuf docs)
|
* DONE writeup nice python options docs (common cases, link to protobuf docs)
|
||||||
* have android app link to user manual
|
* have android app link to user manual
|
||||||
@@ -153,6 +208,44 @@ This should nicely help 'router' nodes do the right thing when long range, or if
|
|||||||
* turn on amazon reviews support
|
* turn on amazon reviews support
|
||||||
* add a tablet layout (with map next to messages) in the android app
|
* add a tablet layout (with map next to messages) in the android app
|
||||||
|
|
||||||
|
# Completed
|
||||||
|
|
||||||
|
## eink 1.0
|
||||||
|
|
||||||
|
* DONE check email of reported issues
|
||||||
|
* DONE turn off vbus driving (in bootloader)
|
||||||
|
* new battery level sensing
|
||||||
|
* current draw no good
|
||||||
|
* DONE: fix backlight
|
||||||
|
* DONE - USB is busted because of power enable mode?
|
||||||
|
* test CPU voltage? something is bad with RAM (removing eink module does not help)
|
||||||
|
* test that board leaves bootloader always
|
||||||
|
* test USB - works in bootloader
|
||||||
|
* test LEDs
|
||||||
|
* Test BME280
|
||||||
|
* test gps
|
||||||
|
* check GPS fast locking
|
||||||
|
* tested! dlora
|
||||||
|
* test eink backlight
|
||||||
|
* tested! eink
|
||||||
|
* test buttons
|
||||||
|
* test battery charging
|
||||||
|
* test serial flash
|
||||||
|
* send updated app and bootloader image
|
||||||
|
* OHH BME280! THAT IS GREAT!
|
||||||
|
* make new screen work, ask for datasheet
|
||||||
|
* say I think you could ship this
|
||||||
|
* leds seem busted
|
||||||
|
* fix hw_model: "nrf52unknown"
|
||||||
|
* use larger icon for meshtastic logo
|
||||||
|
* send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6
|
||||||
|
* send PR for bootloader
|
||||||
|
* fix nrf52 time/date
|
||||||
|
* send new master bin file
|
||||||
|
* send email about low power mode problems
|
||||||
|
* support new flash chip in appload, possibly use low power mode
|
||||||
|
* swbug! stuck busy tx occurred!
|
||||||
|
|
||||||
# Old docs to merge
|
# Old docs to merge
|
||||||
|
|
||||||
MESH RADIO PROTOCOL
|
MESH RADIO PROTOCOL
|
||||||
|
|||||||
@@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
Hi.
|
Hi.
|
||||||
|
|
||||||
If you've landed here that means your android application is too old for the running device firmware. Usually our updates are backwards compatible, but in this special circumstance it is not. Sorry.
|
If you've landed here that means your android application is too old for the running device firmware. Usually our updates are backwards compatible, but about once a year we have a "major protocol update" which requires all apps and devices to update to keep working with that version. Version 1.2 in March 2021 was one of those updates.
|
||||||
|
|
||||||
Probably, what this means is that you installed the **alpha test** version of the firmware from github. We really love people helping with development by running the alpha test binaries. But if you aren't ready to sign up for that right now, please go back to [github](https://github.com/meshtastic/Meshtastic-device/releases) and install the latest **not alpha** 1.1.x firmware.
|
If you have problems/questions please post in our [forum](https://meshtastic.discourse.group) and some nice person will probably help.
|
||||||
|
|
||||||
If you **do** intend to run the alpha test please [opt-in](https://play.google.com/apps/testing/com.geeksville.mesh) to receive the alpha test version of the android application.
|
|
||||||
|
|
||||||
If you are willing to be an alpha tester, please keep an eye on our forum where we post frequent release notes. We also will actively help you with any bugs you might encounter (along our shared journey of new feature goodness).
|
|
||||||
|
|
||||||
If you have problems/questions please post in our [forum](https://meshtastic.discourse.group) and some nice person will probably help.
|
|
||||||
|
|||||||
17
docs/software/channels.md
Normal file
17
docs/software/channels.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Multiple channel support
|
||||||
|
|
||||||
|
Version 1.2 of the software adds support for "multiple (simultaneous) channels". The idea behind this feature is that a mesh can allow multiple users/groups to be share common mesh infrastructure. Even including routing messages for others when no one except that subgroup of users has the encryption keys for their private channel.
|
||||||
|
|
||||||
|
### What is the PRIMARY channel
|
||||||
|
|
||||||
|
The way this works is that each node keeps a list of channels it knows about. One of those channels (normally the first 1) is labelled as the "PRIMARY" channel. The primary channel is the **only** channel that is used to set radio parameters. i.e. this channel controls things like spread factor, coding rate, bandwidth etc... Indirectly this channel also is used to select the specific frequency that all members of this mesh are talking over.
|
||||||
|
|
||||||
|
This channel may or may not have a PSK (encryption). If you are providing mesh to 'the public' we recommend that you always leave this channel with its default psk. The default PSK is technically encrypted (and random users sniffing the ether would have to use meshtastic to decode it), but the key is included in the github source code and you should assume any 'attacker' would have it. But for a 'public' mesh you want this, because it allows anyone using meshtastic in your area to send packets through 'your' mesh.
|
||||||
|
|
||||||
|
Note: Older meshtastic applications that don't yet understand multi-channel support will only show the user this channel.
|
||||||
|
|
||||||
|
### How to use SECONDARY channels
|
||||||
|
|
||||||
|
Any channel you add after that PRIMARY channel is SECONDARY. Secondary channels are used only for encyryption and (in the case of some special applications) security. If you would like to have a private channel over a more public mesh, you probably want to create a SECONDARY channel. When sharing that URL with your private group you will share the "Complete URL". The complete URL includes your secondary channel (for encryption) and the primary channel (to provide radio/mesh access).
|
||||||
|
|
||||||
|
Secondary channels **must** have a PSK (encryption).
|
||||||
@@ -45,12 +45,54 @@ Recommended settings for a sender at different radio settings:
|
|||||||
Medium ... range_test_plugin_sender = 15
|
Medium ... range_test_plugin_sender = 15
|
||||||
Short Fast ... range_test_plugin_sender = 15
|
Short Fast ... range_test_plugin_sender = 15
|
||||||
|
|
||||||
|
## Python API Examples
|
||||||
|
|
||||||
|
### Sender
|
||||||
|
|
||||||
|
meshtastic --set range_test_plugin_enabled 1
|
||||||
|
meshtastic --set range_test_plugin_sender 60
|
||||||
|
|
||||||
|
### Receiver
|
||||||
|
|
||||||
|
meshtastic --set range_test_plugin_enabled 1
|
||||||
|
meshtastic --set range_test_plugin_save 1
|
||||||
|
|
||||||
## Other things to keep in mind
|
## Other things to keep in mind
|
||||||
|
|
||||||
Be sure to turn off either the plugin configured as a sender or the device where the plugin setup as sender when not in use. This will use a lot of time on air and will spam your channel.
|
Be sure to turn off either the plugin configured as a sender or the device where the plugin setup as sender when not in use. This will use a lot of time on air and will spam your channel.
|
||||||
|
|
||||||
Also be mindful of your space usage on the file system. It has protections from filling up the space but it's best to delete old range test results.
|
Also be mindful of your space usage on the file system. It has protections from filling up the space but it's best to delete old range test results.
|
||||||
|
|
||||||
|
# Application Examples
|
||||||
|
|
||||||
|
## Google Integration
|
||||||
|
|
||||||
|
@jfirwin on our forum [meshtastic.discourse.org](https://meshtastic.discourse.group/t/new-plugin-rangetestplugin/2591/49?u=mc-hamster) shared how to integrate the resulting csv file with Google Products.
|
||||||
|
|
||||||
|
### Earth
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
|
||||||
|
1. [Download](https://www.google.com/earth/versions/#download-pro) 1 and open Google Earth
|
||||||
|
1. Select File > Import
|
||||||
|
2. Select CSV
|
||||||
|
3. Select Delimited, Comma
|
||||||
|
4. Make sure the button that states “This dataset does not contain latitude/longitude information, but street addresses” is unchecked
|
||||||
|
5. Select “rx lat” & “rx long” for the appropriate lat/lng fields
|
||||||
|
6. Click finish
|
||||||
|
2. When it prompts you to create a style template, click yes.
|
||||||
|
1. Set the name field to whichever column you want to be displayed on the map (don’t worry about this too much, when you click on an icon, all the relavant data appears)
|
||||||
|
2. select a color, icon, etc. and hit ok.
|
||||||
|
|
||||||
|
Your data will load onto the map, make sure to click the checkbox next to your dataset in the sidebar to view it.
|
||||||
|
|
||||||
|
### My Maps
|
||||||
|
|
||||||
|
You can use [My Maps](http://mymaps.google.com/). It takes CSVs and the whole interface is much easier to work with.
|
||||||
|
|
||||||
|
Google has instructions on how to do that [here](https://support.google.com/mymaps/answer/3024836?co=GENIE.Platform%3DDesktop&hl=en#zippy=%2Cstep-prepare-your-info%2Cstep-import-info-into-the-map).
|
||||||
|
|
||||||
|
You can style the ranges differently based on the values, so you can have the pins be darker the if the SNR or RSSI (if that gets added) is higher.
|
||||||
|
|
||||||
# Known Problems
|
# Known Problems
|
||||||
|
|
||||||
|
|||||||
121
docs/software/remote-admin.md
Normal file
121
docs/software/remote-admin.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# Remote node administration
|
||||||
|
|
||||||
|
This is the first documentation for how to use the [multiple channels](channels.md) feature to enable remote adminstration of meshtastic nodes. i.e. let you talk through the mesh to some far away node and change that nodes settings. This is an advanced feature that (currently) few users would need. Also, keep in mind it is possible (if you are not careful) to assign settings to that remote node that cause it to completely drop off of your mesh.
|
||||||
|
|
||||||
|
Btw: I promised to document how multi-channel is now used to secure remote GPIO/serial access. But probably best to debug these instructions first, so I'll wait on that. If you **do** need to use remote GPIO/serial now, just follow these instructions but name your new channel "gpio" or "serial".
|
||||||
|
|
||||||
|
## Creating the "admin" channel
|
||||||
|
|
||||||
|
Okay - now that we've summarized what multiple-channel support is, we can move on to using it to provide remote administrative access to a node.
|
||||||
|
|
||||||
|
By default, nodes will **only** respond to adminstrative commands via the local USB/bluetooth/TCP interface. This provides basic security to prevent unauthorized access. This is actually how 'normal' administration and settings changes work. The only difference for the remote case is that we are sending those commands over the mesh.
|
||||||
|
|
||||||
|
Before a node will allow remote admin access, it must find a channel
|
||||||
|
```
|
||||||
|
meshtastic --info
|
||||||
|
Connected to radio
|
||||||
|
...
|
||||||
|
Channels:
|
||||||
|
PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }
|
||||||
|
|
||||||
|
Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ
|
||||||
|
```
|
||||||
|
|
||||||
|
So from this output you see that this node knows about only one channel and that its PSK is set to the default value.
|
||||||
|
|
||||||
|
But if you then add an admin channel (with "meshtastic --ch-add admin"). Note: the name is important it must be "admin" (sorry):
|
||||||
|
|
||||||
|
Your channels will now look like this:
|
||||||
|
```
|
||||||
|
meshtastic --ch-add admin
|
||||||
|
Connected to radio
|
||||||
|
Writing modified channels to device
|
||||||
|
|
||||||
|
meshtastic --info
|
||||||
|
Connected to radio
|
||||||
|
...
|
||||||
|
Channels:
|
||||||
|
PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }
|
||||||
|
SECONDARY psk=secret { "psk": "HW7E3nMbiNbvr6MhsDonLCmj7eSAhttzjbIx/r5OQmg=", "name": "admin" }
|
||||||
|
|
||||||
|
Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ
|
||||||
|
Complete URL (includes all channels): https://www.meshtastic.org/d/#CgUYAyIBAQopIiAdbsTecxuI1u-voyGwOicsKaPt5ICG23ONsjH-vk5CaCoFYWRtaW4
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that now we have a new secondary channel. Also, the "--info" option prints out TWO URLs. The "complete URL" includes all of the channels this node understands. You should consider this URL something you should be very cautious about sharing. In the case of remote adminstration, you only need the node you want to adminster and the node you are locally connected to know this new "admin" channel.
|
||||||
|
|
||||||
|
## Sharing the admin channel with other nodes
|
||||||
|
|
||||||
|
I'm going to assume you've already created the admin channel on your "local node" i.e. the meshtastic node sitting on your desk at your home. But now you want to enable access on the "remote node" you want to eventually have far away from you.
|
||||||
|
|
||||||
|
For this step you need physical access to both the nodes.
|
||||||
|
|
||||||
|
1. Create the "admin" channel on the "local node" using the instructions above.
|
||||||
|
2. Copy the "Complete URL" someplace for permanent reference/access.
|
||||||
|
3. Connect meshtastic-python to the "remote node" over the USB port.
|
||||||
|
4. For the "remote node" type "meshtastic --seturl the-url-from-step-2".
|
||||||
|
5. Run "meshtastic --info" and confirm that the "Complete URL" is the same for both of the nodes.
|
||||||
|
6. Done!
|
||||||
|
|
||||||
|
At this point you can take your remote node and install it far away and still be able to change any of its settings.
|
||||||
|
|
||||||
|
## Remotely administering your node
|
||||||
|
|
||||||
|
Now that both your local node and the remote node contain your secret admin channel key, you can do things like this:
|
||||||
|
|
||||||
|
Get the node list from the local node.
|
||||||
|
|
||||||
|
```
|
||||||
|
meshtastic --nodes
|
||||||
|
Connected to radio
|
||||||
|
/----------------------------------------------------------------------------------------------------------\
|
||||||
|
|N| User |AKA| ID | Position |Battery| SNR | LastHeard | Since |
|
||||||
|
|-+------------+---+---------+------------------------+-------+---------+-------------------+--------------|
|
||||||
|
|1|Unknown 9058|?58|!28979058|25.0382°, 121.5731°, N/A| N/A |-13.50 dB|2021-03-22 09:25:42|19 seconds ago|
|
||||||
|
\----------------------------------------------------------------------------------------------------------/
|
||||||
|
```
|
||||||
|
|
||||||
|
Using the node ID from that list, send a message through the mesh telling that node to change its owner name.
|
||||||
|
|
||||||
|
```
|
||||||
|
meshtastic --dest \!28979058 --set-owner "Im Remote"
|
||||||
|
Connected to radio
|
||||||
|
Setting device owner to Im Remote
|
||||||
|
INFO:root:Requesting configuration from remote node (this could take a while)
|
||||||
|
```
|
||||||
|
|
||||||
|
And you can now confirm via the local node that the remote node has changed:
|
||||||
|
|
||||||
|
```
|
||||||
|
meshtastic --nodes
|
||||||
|
Connected to radio
|
||||||
|
/----------------------------------------------------------------------------------------------------\
|
||||||
|
|N| User |AKA| ID | Position |Battery| SNR | LastHeard | Since |
|
||||||
|
|-+---------+---+---------+------------------------+-------+-------+-------------------+-------------|
|
||||||
|
|1|Im Remote|IR |!28979058|25.0382°, 121.5731°, N/A| N/A |8.75 dB|2021-03-22 09:35:42|3 minutes ago|
|
||||||
|
\----------------------------------------------------------------------------------------------------/
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: you can change **any** parameter, add channels or get info from the remote node. Here's an example of setting ls_secs and printing the complete device info from the remote node.
|
||||||
|
|
||||||
|
```
|
||||||
|
meshtastic --dest \!28979058 --set ls_secs 301 --info
|
||||||
|
Connected to radio
|
||||||
|
INFO:root:Requesting configuration from remote node (this could take a while)
|
||||||
|
Set ls_secs to 301
|
||||||
|
Writing modified preferences to device
|
||||||
|
|
||||||
|
|
||||||
|
Preferences: { "lsSecs": 301, "region": "TW" }
|
||||||
|
|
||||||
|
Channels:
|
||||||
|
PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }
|
||||||
|
SECONDARY psk=secret { "psk": "HW7E3nMbiNbvr6MhsDonLCmj7eSAhttzjbIx/r5OQmg=", "name": "admin" }
|
||||||
|
|
||||||
|
Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ
|
||||||
|
Complete URL (includes all channels): https://www.meshtastic.org/d/#CgUYAyIBAQopIiAdbsTecxuI1u-voyGwOicsKaPt5ICG23ONsjH-vk5CaCoFYWRtaW4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Areas for future development
|
||||||
|
|
||||||
|
In the future we will add a "deadman timer" to this feature so that the remote node will revert any changes if you fail to send a special "commit changes" command. This will protect against sending bad settings to nodes that you can't physically access. Instead if the node does not receive a commit message within 10 minutes it will revert all changes and (hopefully) rejoin the mesh.
|
||||||
10
docs/software/running-github-actions.md
Normal file
10
docs/software/running-github-actions.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Running github actions locally
|
||||||
|
|
||||||
|
If you'd like to run the **same** integration tests we run on github but on your own machine, you can do the following.
|
||||||
|
|
||||||
|
1. Install homebrew per https://brew.sh/
|
||||||
|
2. Install https://github.com/nektos/act with "brew install act"
|
||||||
|
3. cd into meshtastic-device and run "act"
|
||||||
|
4. Select a "medium" sized image
|
||||||
|
5. Alas - this "act" build **almost** works, but fails because it can't find lib/nanopb/include/pb.h! So someone (you the reader? @geeksville ays hopefully...) needs to fix that before these instructions are complete.
|
||||||
|
6.
|
||||||
@@ -6,5 +6,7 @@ This is a mini design doc for developing the meshtastic software.
|
|||||||
* Our [project board](https://github.com/orgs/meshtastic/projects/1) - shows what things we are currently working on and remaining work items for the current release.
|
* Our [project board](https://github.com/orgs/meshtastic/projects/1) - shows what things we are currently working on and remaining work items for the current release.
|
||||||
* [Power Management](power.md)
|
* [Power Management](power.md)
|
||||||
* [Mesh algorithm](mesh-alg.md)
|
* [Mesh algorithm](mesh-alg.md)
|
||||||
|
* [Channels](channels.md) - documentation on how multiple simultaneous channels are used
|
||||||
|
* [Remote adminstration](remote-admin.md)
|
||||||
* [External client API](device-api.md) and porting guide for new clients (iOS, python, etc...)
|
* [External client API](device-api.md) and porting guide for new clients (iOS, python, etc...)
|
||||||
* TODO: how to port the device code to a new device.
|
* TODO: how to port the device code to a new device.
|
||||||
|
|||||||
@@ -13,10 +13,12 @@ default_envs = tbeam
|
|||||||
;default_envs = tbeam0.7
|
;default_envs = tbeam0.7
|
||||||
;default_envs = heltec
|
;default_envs = heltec
|
||||||
;default_envs = tlora-v1
|
;default_envs = tlora-v1
|
||||||
|
;default_envs = tlora_v1_3
|
||||||
;default_envs = tlora-v2
|
;default_envs = tlora-v2
|
||||||
;default_envs = lora-relay-v1 # nrf board
|
;default_envs = lora-relay-v1 # nrf board
|
||||||
;default_envs = eink
|
;default_envs = eink
|
||||||
;default_envs = linux # 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 = 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
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
; common is not currently used
|
; common is not currently used
|
||||||
@@ -33,21 +35,16 @@ default_envs = tbeam
|
|||||||
extra_scripts = bin/platformio-custom.py
|
extra_scripts = bin/platformio-custom.py
|
||||||
|
|
||||||
; note: we add src to our include search path so that lmic_project_config can override
|
; note: we add src to our include search path so that lmic_project_config can override
|
||||||
|
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
|
||||||
|
; of code is a heap corruption bug!
|
||||||
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
|
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
|
||||||
build_flags = -Wno-missing-field-initializers
|
build_flags = -Wno-missing-field-initializers
|
||||||
-Wno-format
|
-Wno-format
|
||||||
-Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map
|
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||||
-DHW_VERSION_${sysenv.COUNTRY}
|
-DHW_VERSION_${sysenv.COUNTRY}
|
||||||
-DHW_VERSION=${sysenv.HW_VERSION}
|
-DHW_VERSION=${sysenv.HW_VERSION}
|
||||||
-DUSE_THREAD_NAMES
|
-DUSE_THREAD_NAMES
|
||||||
-DTINYGPSPLUS_OPTION_NO_CUSTOM_FIELDS
|
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||||
|
|
||||||
; leave this commented out to avoid breaking Windows
|
|
||||||
;upload_port = /dev/ttyUSB0
|
|
||||||
;monitor_port = /dev/ttyUSB0
|
|
||||||
|
|
||||||
;upload_port = /dev/cu.SLAB_USBtoUART
|
|
||||||
;monitor_port = /dev/cu.SLAB_USBtoUART
|
|
||||||
|
|
||||||
; the default is esptool
|
; the default is esptool
|
||||||
; upload_protocol = esp-prog
|
; upload_protocol = esp-prog
|
||||||
@@ -71,10 +68,10 @@ lib_deps =
|
|||||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
|
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
|
||||||
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
|
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
|
||||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||||
https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
|
https://github.com/meshtastic/arduino-fsm.git#829e967b8a95c094f73c60ef8dacfe66eae38940
|
||||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||||
https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a
|
https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a
|
||||||
https://github.com/meshtastic/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206
|
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
|
||||||
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||||
SPI
|
SPI
|
||||||
@@ -113,7 +110,14 @@ lib_deps =
|
|||||||
# board_build.ldscript = linker/esp32.extram.bss.ld
|
# board_build.ldscript = linker/esp32.extram.bss.ld
|
||||||
lib_ignore = segger_rtt
|
lib_ignore = segger_rtt
|
||||||
platform_packages =
|
platform_packages =
|
||||||
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#352c8ea7cb73f10433ed139f34251979c470ad56
|
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276
|
||||||
|
|
||||||
|
; leave this commented out to avoid breaking Windows
|
||||||
|
upload_port = /dev/ttyUSB0
|
||||||
|
;monitor_port = /dev/ttyUSB0
|
||||||
|
|
||||||
|
;upload_port = /dev/cu.SLAB_USBtoUART
|
||||||
|
;monitor_port = /dev/cu.SLAB_USBtoUART
|
||||||
|
|
||||||
; customize the partition table
|
; customize the partition table
|
||||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||||
@@ -155,6 +159,12 @@ build_flags =
|
|||||||
${esp32_base.build_flags} -D TLORA_V1
|
${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
|
; 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]
|
[env:tlora-v2]
|
||||||
extends = esp32_base
|
extends = esp32_base
|
||||||
board = ttgo-lora32-v1
|
board = ttgo-lora32-v1
|
||||||
@@ -184,7 +194,6 @@ src_filter =
|
|||||||
; platform = nordicnrf52
|
; platform = nordicnrf52
|
||||||
platform = https://github.com/meshtastic/platform-nordicnrf52.git#1a2639a6b0f79b5df66bea3e3089f0d5285fdc63
|
platform = https://github.com/meshtastic/platform-nordicnrf52.git#1a2639a6b0f79b5df66bea3e3089f0d5285fdc63
|
||||||
extends = arduino_base
|
extends = arduino_base
|
||||||
debug_tool = jlink
|
|
||||||
build_type = debug ; I'm debugging with ICE a lot now
|
build_type = debug ; I'm debugging with ICE a lot now
|
||||||
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
|
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
|
||||||
build_flags =
|
build_flags =
|
||||||
@@ -198,6 +207,27 @@ lib_ignore =
|
|||||||
BluetoothOTA
|
BluetoothOTA
|
||||||
monitor_port = /dev/ttyACM1
|
monitor_port = /dev/ttyACM1
|
||||||
|
|
||||||
|
# we pass in options to jlink so it can understand freertos (note: we don't use "jlink" as the tool)
|
||||||
|
debug_tool = jlink
|
||||||
|
debug_port = :2331
|
||||||
|
# Note: the ARGUMENTS MUST BE on multiple lines. Otherwise platformio/commands/debug/helpers.py misparses everything into the "executable"
|
||||||
|
# attribute and leaves "arguments" empty
|
||||||
|
# /home/kevinh/.platformio/packages/tool-jlink/JLinkGDBServerCLExe
|
||||||
|
# This doesn't work yet, so not using for now
|
||||||
|
disabled_debug_server =
|
||||||
|
/usr/bin/JLinkGDBServerCLExe
|
||||||
|
-singlerun
|
||||||
|
-if
|
||||||
|
SWD
|
||||||
|
-select
|
||||||
|
USB
|
||||||
|
-device
|
||||||
|
nRF52840_xxAA
|
||||||
|
-port
|
||||||
|
2331
|
||||||
|
-rtos
|
||||||
|
GDBServer/RTOSPlugin_FreeRTOS
|
||||||
|
|
||||||
debug_extra_cmds =
|
debug_extra_cmds =
|
||||||
source gdbinit
|
source gdbinit
|
||||||
|
|
||||||
@@ -209,6 +239,24 @@ debug_init_break =
|
|||||||
;debug_init_break = tbreak loop
|
;debug_init_break = tbreak loop
|
||||||
;debug_init_break = tbreak Reset_Handler
|
;debug_init_break = tbreak Reset_Handler
|
||||||
|
|
||||||
|
[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
|
; The NRF52840-dk development board
|
||||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||||
[env:nrf52840dk]
|
[env:nrf52840dk]
|
||||||
@@ -332,19 +380,20 @@ lib_deps =
|
|||||||
TFT_eSPI
|
TFT_eSPI
|
||||||
|
|
||||||
; The Portduino based sim environment on top of linux
|
; The Portduino based sim environment on top of linux
|
||||||
[env:linux]
|
[env:native]
|
||||||
platform = https://github.com/geeksville/platform-portduino.git
|
platform = https://github.com/geeksville/platform-native.git
|
||||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
||||||
build_flags = ${arduino_base.build_flags} -O0
|
build_flags = ${arduino_base.build_flags} -O0
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = linux_x86_64
|
board = native
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${arduino_base.lib_deps}
|
${arduino_base.lib_deps}
|
||||||
rweather/Crypto
|
rweather/Crypto
|
||||||
|
|
||||||
; The GenieBlocks LORA prototype board
|
; The GenieBlocks LORA prototype board
|
||||||
[env:genieblocks_lora]
|
; note: @geeksville disabled because genieblocks_lora is not checked into the boards directory, please send in a PR to add it ;-)
|
||||||
extends = esp32_base
|
;[env:genieblocks_lora]
|
||||||
board = genieblocks_lora
|
;extends = esp32_base
|
||||||
build_flags =
|
;board = genieblocks_lora
|
||||||
${esp32_base.build_flags} -D GENIEBLOCKS
|
;build_flags =
|
||||||
|
; ${esp32_base.build_flags} -D GENIEBLOCKS
|
||||||
2
proto
2
proto
Submodule proto updated: 7c025b9a4d...2aa1439214
@@ -40,7 +40,7 @@ bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2
|
|||||||
tParam1 = param1;
|
tParam1 = param1;
|
||||||
tParam2 = param2;
|
tParam2 = param2;
|
||||||
|
|
||||||
timerAlarmWrite(timer, delayMsec * 1000L, false); // Do not reload, we want it to be a single shot timer
|
timerAlarmWrite(timer, delayMsec * 1000UL, false); // Do not reload, we want it to be a single shot timer
|
||||||
timerRestart(timer);
|
timerRestart(timer);
|
||||||
timerAlarmEnable(timer);
|
timerAlarmEnable(timer);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -5,12 +5,35 @@
|
|||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
#ifdef TBEAM_V10
|
||||||
// FIXME. nasty hack cleanup how we load axp192
|
// FIXME. nasty hack cleanup how we load axp192
|
||||||
#undef AXP192_SLAVE_ADDRESS
|
#undef AXP192_SLAVE_ADDRESS
|
||||||
#include "axp20x.h"
|
#include "axp20x.h"
|
||||||
|
|
||||||
#ifdef TBEAM_V10
|
|
||||||
AXP20X_Class axp;
|
AXP20X_Class axp;
|
||||||
|
#else
|
||||||
|
// Copy of the base class defined in axp20x.h.
|
||||||
|
// I'd rather not inlude axp20x.h as it brings Wire dependency.
|
||||||
|
class HasBatteryLevel {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||||
|
*/
|
||||||
|
virtual int getBattPercentage() { return -1; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw voltage of the battery or NAN if unknown
|
||||||
|
*/
|
||||||
|
virtual float getBattVoltage() { return NAN; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if there is a battery installed in this unit
|
||||||
|
*/
|
||||||
|
virtual bool isBatteryConnect() { return false; }
|
||||||
|
|
||||||
|
virtual bool isVBUSPlug() { return false; }
|
||||||
|
virtual bool isChargeing() { return false; }
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool pmu_irq = false;
|
bool pmu_irq = false;
|
||||||
@@ -51,7 +74,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
*/
|
*/
|
||||||
virtual int getBattPercentage()
|
virtual int getBattPercentage()
|
||||||
{
|
{
|
||||||
float v = getBattVoltage() / 1000;
|
float v = getBattVoltage();
|
||||||
|
|
||||||
if (v < noBatVolt)
|
if (v < noBatVolt)
|
||||||
return -1; // If voltage is super low assume no battery installed
|
return -1; // If voltage is super low assume no battery installed
|
||||||
@@ -67,13 +90,26 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
*/
|
*/
|
||||||
virtual float getBattVoltage()
|
virtual float getBattVoltage()
|
||||||
{
|
{
|
||||||
// Tested ttgo eink nrf52 board and the reported value is perfect
|
|
||||||
// DEBUG_MSG("raw val %u", raw);
|
#ifndef ADC_MULTIPLIER
|
||||||
return
|
#define ADC_MULTIPLIER 2.0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BATTERY_PIN
|
#ifdef BATTERY_PIN
|
||||||
1000.0 * 2.0 * (AREF_VOLTAGE / 1024.0) * analogRead(BATTERY_PIN);
|
// Do not call analogRead() often.
|
||||||
|
const uint32_t min_read_interval = 5000;
|
||||||
|
if (millis() - last_read_time_ms > min_read_interval) {
|
||||||
|
last_read_time_ms = millis();
|
||||||
|
uint32_t raw = analogRead(BATTERY_PIN);
|
||||||
|
float scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
|
||||||
|
// DEBUG_MSG("raw val=%u scaled=%u\n", raw, (uint32_t)(scaled));
|
||||||
|
last_read_value = scaled;
|
||||||
|
return scaled;
|
||||||
|
} else {
|
||||||
|
return last_read_value;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
NAN;
|
return NAN;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +129,9 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
private:
|
private:
|
||||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||||
/// in power
|
/// in power
|
||||||
const float fullVolt = 4.2, emptyVolt = 3.27, chargingVolt = 4.3, noBatVolt = 2.1;
|
const float fullVolt = 4200, emptyVolt = 3270, chargingVolt = 4210, noBatVolt = 2100;
|
||||||
|
float last_read_value = 0.0;
|
||||||
|
uint32_t last_read_time_ms = 0;
|
||||||
} analogLevel;
|
} analogLevel;
|
||||||
|
|
||||||
Power::Power() : OSThread("Power") {}
|
Power::Power() : OSThread("Power") {}
|
||||||
@@ -140,6 +178,8 @@ void Power::shutdown()
|
|||||||
#ifdef TBEAM_V10
|
#ifdef TBEAM_V10
|
||||||
DEBUG_MSG("Shutting down\n");
|
DEBUG_MSG("Shutting down\n");
|
||||||
axp.shutdown();
|
axp.shutdown();
|
||||||
|
#elif NRF52_SERIES
|
||||||
|
doDeepSleep(DELAY_FOREVER);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
102
src/PowerFSM.cpp
102
src/PowerFSM.cpp
@@ -9,6 +9,23 @@
|
|||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
|
|
||||||
|
/// Should we behave as if we have AC power now?
|
||||||
|
static bool isPowered()
|
||||||
|
{
|
||||||
|
bool isRouter = radioConfig.preferences.is_router;
|
||||||
|
|
||||||
|
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
|
||||||
|
// We assume routers might be powered all the time, but from a low current (solar) source
|
||||||
|
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
|
||||||
|
|
||||||
|
/* To determine if we're externally powered, assumptions
|
||||||
|
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
|
||||||
|
|
||||||
|
2) If we detect USB power from the power management chip, we must be getting power externally.
|
||||||
|
*/
|
||||||
|
return !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||||
|
}
|
||||||
|
|
||||||
static void sdsEnter()
|
static void sdsEnter()
|
||||||
{
|
{
|
||||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||||
@@ -97,7 +114,8 @@ static void lsIdle()
|
|||||||
static void lsExit()
|
static void lsExit()
|
||||||
{
|
{
|
||||||
// setGPSPower(true); // restore GPS power
|
// setGPSPower(true); // restore GPS power
|
||||||
gps->forceWake(true);
|
if (gps)
|
||||||
|
gps->forceWake(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nbEnter()
|
static void nbEnter()
|
||||||
@@ -118,14 +136,34 @@ static void serialEnter()
|
|||||||
{
|
{
|
||||||
setBluetoothEnable(false);
|
setBluetoothEnable(false);
|
||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
screen->print("Using API...\n");
|
screen->print("Serial connected\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serialExit()
|
||||||
|
{
|
||||||
|
screen->print("Serial disconnected\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void powerEnter()
|
static void powerEnter()
|
||||||
{
|
{
|
||||||
screen->setOn(true);
|
if (!isPowered()) {
|
||||||
setBluetoothEnable(true);
|
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||||
screen->print("Powered...\n");
|
DEBUG_MSG("Loss of power in Powered\n");
|
||||||
|
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||||
|
} else {
|
||||||
|
screen->setOn(true);
|
||||||
|
setBluetoothEnable(true);
|
||||||
|
screen->print("Powered...\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void powerIdle()
|
||||||
|
{
|
||||||
|
if (!isPowered()) {
|
||||||
|
// If we got here, we are in the wrong state
|
||||||
|
DEBUG_MSG("Loss of power in Powered\n");
|
||||||
|
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void powerExit()
|
static void powerExit()
|
||||||
@@ -152,6 +190,14 @@ static void onEnter()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void onIdle()
|
||||||
|
{
|
||||||
|
if (isPowered()) {
|
||||||
|
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||||
|
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void screenPress()
|
static void screenPress()
|
||||||
{
|
{
|
||||||
screen->onPress();
|
screen->onPress();
|
||||||
@@ -163,26 +209,16 @@ State stateSDS(sdsEnter, NULL, NULL, "SDS");
|
|||||||
State stateLS(lsEnter, lsIdle, lsExit, "LS");
|
State stateLS(lsEnter, lsIdle, lsExit, "LS");
|
||||||
State stateNB(nbEnter, NULL, NULL, "NB");
|
State stateNB(nbEnter, NULL, NULL, "NB");
|
||||||
State stateDARK(darkEnter, NULL, NULL, "DARK");
|
State stateDARK(darkEnter, NULL, NULL, "DARK");
|
||||||
State stateSERIAL(serialEnter, NULL, NULL, "SERIAL");
|
State stateSERIAL(serialEnter, NULL, serialExit, "SERIAL");
|
||||||
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
|
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
|
||||||
State stateON(onEnter, NULL, NULL, "ON");
|
State stateON(onEnter, onIdle, NULL, "ON");
|
||||||
State statePOWER(powerEnter, NULL, powerExit, "POWER");
|
State statePOWER(powerEnter, powerIdle, powerExit, "POWER");
|
||||||
Fsm powerFSM(&stateBOOT);
|
Fsm powerFSM(&stateBOOT);
|
||||||
|
|
||||||
void PowerFSM_setup()
|
void PowerFSM_setup()
|
||||||
{
|
{
|
||||||
bool isRouter = radioConfig.preferences.is_router;
|
bool isRouter = radioConfig.preferences.is_router;
|
||||||
|
bool hasPower = isPowered();
|
||||||
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
|
|
||||||
// We assume routers might be powered all the time, but from a low current (solar) source
|
|
||||||
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
|
|
||||||
|
|
||||||
/* To determine if we're externally powered, assumptions
|
|
||||||
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
|
|
||||||
|
|
||||||
2) If we detect USB power from the power management chip, we must be getting power externally.
|
|
||||||
*/
|
|
||||||
bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
|
||||||
|
|
||||||
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
|
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
|
||||||
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
|
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
|
||||||
@@ -230,25 +266,33 @@ void PowerFSM_setup()
|
|||||||
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
|
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are not in statePOWER but get a serial connection, suppress sleep (and keep the screen on) while connected
|
||||||
powerFSM.add_transition(&stateLS, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
powerFSM.add_transition(&stateLS, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||||
powerFSM.add_transition(&stateNB, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
powerFSM.add_transition(&stateNB, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||||
powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||||
powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||||
|
powerFSM.add_transition(&statePOWER, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||||
|
|
||||||
if (!isLowPower) {
|
// If we get power connected, go to the power connect state
|
||||||
powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||||
powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||||
powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||||
powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||||
}
|
|
||||||
|
|
||||||
powerFSM.add_transition(&statePOWER, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
|
powerFSM.add_transition(&statePOWER, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
|
||||||
powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
|
// powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
|
||||||
|
|
||||||
powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
|
// the only way to leave state serial is for the client to disconnect (or we timeout and force disconnect them)
|
||||||
|
// when we leave, go to ON (which might not be the correct state if we have power connected, we will fix that in onEnter)
|
||||||
|
powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
|
||||||
|
|
||||||
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
||||||
|
|
||||||
|
// each time we get a new update packet make sure we are staying in the ON state so the screen stays awake (also we don't
|
||||||
|
// shutdown bluetooth if is_router)
|
||||||
|
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||||
|
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||||
|
|
||||||
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
|
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
|
||||||
|
|
||||||
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
|
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
|
||||||
@@ -259,7 +303,9 @@ void PowerFSM_setup()
|
|||||||
#ifndef NRF52_SERIES
|
#ifndef NRF52_SERIES
|
||||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||||
|
|
||||||
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
|
// I don't think this transition is correct, turning off for now - @geeksville
|
||||||
|
// powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
|
||||||
|
|
||||||
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
|
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
|
||||||
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
|
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#define EVENT_SERIAL_DISCONNECTED 12
|
#define EVENT_SERIAL_DISCONNECTED 12
|
||||||
#define EVENT_POWER_CONNECTED 13
|
#define EVENT_POWER_CONNECTED 13
|
||||||
#define EVENT_POWER_DISCONNECTED 14
|
#define EVENT_POWER_DISCONNECTED 14
|
||||||
|
#define EVENT_FIRMWARE_UPDATE 15 // We just received a new firmware update packet from the phone
|
||||||
|
|
||||||
extern Fsm powerFSM;
|
extern Fsm powerFSM;
|
||||||
extern State statePOWER, stateSERIAL;
|
extern State statePOWER, stateSERIAL;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#include "RedirectablePrint.h"
|
#include "RedirectablePrint.h"
|
||||||
|
#include "RTC.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "concurrency/OSThread.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A printer that doesn't go anywhere
|
* A printer that doesn't go anywhere
|
||||||
@@ -20,11 +21,12 @@ size_t RedirectablePrint::write(uint8_t c)
|
|||||||
{
|
{
|
||||||
// Always send the characters to our segger JTAG debugger
|
// Always send the characters to our segger JTAG debugger
|
||||||
#ifdef SEGGER_STDOUT_CH
|
#ifdef SEGGER_STDOUT_CH
|
||||||
SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c);
|
SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dest->write(c);
|
dest->write(c);
|
||||||
return 1; // We always claim one was written, rather than trusting what the serial port said (which could be zero)
|
return 1; // We always claim one was written, rather than trusting what the
|
||||||
|
// serial port said (which could be zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||||
@@ -38,7 +40,7 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
|||||||
va_end(arg);
|
va_end(arg);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
if (len >= printBufLen) {
|
if (len >= (int)printBufLen) {
|
||||||
delete[] printBuf;
|
delete[] printBuf;
|
||||||
printBufLen *= 2;
|
printBufLen *= 2;
|
||||||
printBuf = new char[printBufLen];
|
printBuf = new char[printBufLen];
|
||||||
@@ -49,51 +51,54 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SEC_PER_DAY 86400
|
|
||||||
#define SEC_PER_HOUR 3600
|
|
||||||
#define SEC_PER_MIN 60
|
|
||||||
|
|
||||||
size_t RedirectablePrint::logDebug(const char *format, ...)
|
size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list arg;
|
|
||||||
va_start(arg, format);
|
|
||||||
|
|
||||||
// Cope with 0 len format strings, but look for new line terminator
|
|
||||||
bool hasNewline = *format && format[strlen(format) - 1] == '\n';
|
|
||||||
|
|
||||||
size_t r = 0;
|
size_t r = 0;
|
||||||
|
|
||||||
// If we are the first message on a report, include the header
|
if (!inDebugPrint) {
|
||||||
if (!isContinuationMessage) {
|
inDebugPrint = true;
|
||||||
struct timeval tv;
|
|
||||||
if (!gettimeofday(&tv, NULL)) {
|
|
||||||
long hms = tv.tv_sec % SEC_PER_DAY;
|
|
||||||
//hms += tz.tz_dsttime * SEC_PER_HOUR;
|
|
||||||
//hms -= tz.tz_minuteswest * SEC_PER_MIN;
|
|
||||||
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
|
|
||||||
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
|
||||||
|
|
||||||
// Tear apart hms into h:m:s
|
va_list arg;
|
||||||
int hour = hms / SEC_PER_HOUR;
|
va_start(arg, format);
|
||||||
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
|
||||||
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
|
||||||
|
|
||||||
r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
|
// Cope with 0 len format strings, but look for new line terminator
|
||||||
} else
|
bool hasNewline = *format && format[strlen(format) - 1] == '\n';
|
||||||
r += printf("??:??:?? %u ", millis() / 1000);
|
|
||||||
|
|
||||||
auto thread = concurrency::OSThread::currentThread;
|
// If we are the first message on a report, include the header
|
||||||
if(thread) {
|
if (!isContinuationMessage) {
|
||||||
print("[");
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
|
||||||
print(thread->ThreadName);
|
if (rtc_sec > 0) {
|
||||||
print("] ");
|
long hms = rtc_sec % SEC_PER_DAY;
|
||||||
|
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||||||
|
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
|
||||||
|
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
|
||||||
|
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||||||
|
|
||||||
|
// Tear apart hms into h:m:s
|
||||||
|
int hour = hms / SEC_PER_HOUR;
|
||||||
|
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||||
|
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||||||
|
|
||||||
|
r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
|
||||||
|
} else
|
||||||
|
r += printf("??:??:?? %u ", millis() / 1000);
|
||||||
|
|
||||||
|
auto thread = concurrency::OSThread::currentThread;
|
||||||
|
if (thread) {
|
||||||
|
print("[");
|
||||||
|
// printf("%p ", thread);
|
||||||
|
// assert(thread->ThreadName.length());
|
||||||
|
print(thread->ThreadName);
|
||||||
|
print("] ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r += vprintf(format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
isContinuationMessage = !hasNewline;
|
||||||
|
inDebugPrint = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r += vprintf(format, arg);
|
|
||||||
va_end(arg);
|
|
||||||
|
|
||||||
isContinuationMessage = !hasNewline;
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,8 @@ class RedirectablePrint : public Print
|
|||||||
/// Used to allow multiple logDebug messages to appear on a single log line
|
/// Used to allow multiple logDebug messages to appear on a single log line
|
||||||
bool isContinuationMessage = false;
|
bool isContinuationMessage = false;
|
||||||
|
|
||||||
|
volatile bool inDebugPrint = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RedirectablePrint(Print *_dest) : dest(_dest) {}
|
RedirectablePrint(Print *_dest) : dest(_dest) {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,34 @@
|
|||||||
#include "SerialConsole.h"
|
#include "SerialConsole.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "NodeDB.h"
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#define Port Serial
|
#define Port Serial
|
||||||
|
|
||||||
SerialConsole console;
|
SerialConsole *console;
|
||||||
|
|
||||||
|
void consoleInit()
|
||||||
|
{
|
||||||
|
new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
|
||||||
|
}
|
||||||
|
|
||||||
|
void consolePrintf(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
va_start(arg, format);
|
||||||
|
console->vprintf(format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
}
|
||||||
|
|
||||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||||
{
|
{
|
||||||
|
assert(!console);
|
||||||
|
console = this;
|
||||||
canWrite = false; // We don't send packets to our port until it has talked to us first
|
canWrite = false; // We don't send packets to our port until it has talked to us first
|
||||||
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
||||||
}
|
|
||||||
|
|
||||||
/// Do late init that can't happen at constructor time
|
|
||||||
void SerialConsole::init()
|
|
||||||
{
|
|
||||||
Port.begin(SERIAL_BAUD);
|
Port.begin(SERIAL_BAUD);
|
||||||
StreamAPI::init();
|
|
||||||
emitRebooted();
|
emitRebooted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,14 +36,14 @@ void SerialConsole::init()
|
|||||||
* we override this to notice when we've received a protobuf over the serial
|
* we override this to notice when we've received a protobuf over the serial
|
||||||
* stream. Then we shunt off debug serial output.
|
* stream. Then we shunt off debug serial output.
|
||||||
*/
|
*/
|
||||||
void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||||
if(!radioConfig.preferences.debug_log_enabled)
|
if (!radioConfig.preferences.debug_log_enabled)
|
||||||
setDestination(&noopPrint);
|
setDestination(&noopPrint);
|
||||||
canWrite = true;
|
canWrite = true;
|
||||||
|
|
||||||
StreamAPI::handleToRadio(buf, len);
|
return StreamAPI::handleToRadio(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hookable to find out when connection changes
|
/// Hookable to find out when connection changes
|
||||||
|
|||||||
@@ -11,14 +11,11 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
|||||||
public:
|
public:
|
||||||
SerialConsole();
|
SerialConsole();
|
||||||
|
|
||||||
/// Do late init that can't happen at constructor time
|
|
||||||
virtual void init();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
|
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
|
||||||
* debug serial output.
|
* debug serial output.
|
||||||
*/
|
*/
|
||||||
virtual void handleToRadio(const uint8_t *buf, size_t len);
|
virtual bool handleToRadio(const uint8_t *buf, size_t len);
|
||||||
|
|
||||||
virtual size_t write(uint8_t c)
|
virtual size_t write(uint8_t c)
|
||||||
{
|
{
|
||||||
@@ -32,4 +29,8 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
|||||||
virtual void onConnectionChanged(bool connected);
|
virtual void onConnectionChanged(bool connected);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SerialConsole console;
|
// A simple wrapper to allow non class aware code write to the console
|
||||||
|
void consolePrintf(const char *format, ...);
|
||||||
|
void consoleInit();
|
||||||
|
|
||||||
|
extern SerialConsole *console;
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ class AirTime : private concurrency::OSThread
|
|||||||
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
|
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual int32_t runOnce() override;
|
||||||
virtual int32_t runOnce();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern AirTime *airTime;
|
extern AirTime *airTime;
|
||||||
66
src/buzz/buzz.cpp
Normal file
66
src/buzz/buzz.cpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#include "buzz.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#ifdef NRF52_SERIES
|
||||||
|
#include "variant.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_BUZZER
|
||||||
|
|
||||||
|
// Noop methods for boards w/o buzzer
|
||||||
|
void playBeep(){};
|
||||||
|
void playStartMelody(){};
|
||||||
|
void playShutdownMelody(){};
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include "Tone.h"
|
||||||
|
|
||||||
|
extern "C" void delay(uint32_t dwMs);
|
||||||
|
|
||||||
|
struct ToneDuration {
|
||||||
|
int frequency_khz;
|
||||||
|
int duration_ms;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Some common frequencies.
|
||||||
|
#define NOTE_C3 131
|
||||||
|
#define NOTE_CS3 139
|
||||||
|
#define NOTE_D3 147
|
||||||
|
#define NOTE_DS3 156
|
||||||
|
#define NOTE_E3 165
|
||||||
|
#define NOTE_F3 175
|
||||||
|
#define NOTE_FS3 185
|
||||||
|
#define NOTE_G3 196
|
||||||
|
#define NOTE_GS3 208
|
||||||
|
#define NOTE_A3 220
|
||||||
|
#define NOTE_AS3 233
|
||||||
|
#define NOTE_B3 247
|
||||||
|
|
||||||
|
const int DURATION_1_8 = 125; // 1/8 note
|
||||||
|
const int DURATION_1_4 = 250; // 1/4 note
|
||||||
|
|
||||||
|
void playTones(const ToneDuration *tone_durations, int size) {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
const auto &tone_duration = tone_durations[i];
|
||||||
|
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||||
|
// to distinguish the notes, set a minimum time between them.
|
||||||
|
delay(1.3 * tone_duration.duration_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
|
||||||
|
|
||||||
|
void playStartMelody() {
|
||||||
|
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||||
|
{NOTE_B3, DURATION_1_8},
|
||||||
|
{NOTE_B3, DURATION_1_8}};
|
||||||
|
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
void playShutdownMelody() {
|
||||||
|
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||||
|
{NOTE_G3, DURATION_1_8},
|
||||||
|
{NOTE_D3, DURATION_1_8}};
|
||||||
|
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
5
src/buzz/buzz.h
Normal file
5
src/buzz/buzz.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void playBeep();
|
||||||
|
void playStartMelody();
|
||||||
|
void playShutdownMelody();
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "concurrency/BinarySemaphoreFreeRTOS.h"
|
#include "concurrency/BinarySemaphoreFreeRTOS.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef HAS_FREE_RTOS
|
#ifdef HAS_FREE_RTOS
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ namespace concurrency
|
|||||||
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS()
|
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS()
|
||||||
{
|
{
|
||||||
semaphore = xSemaphoreCreateBinary();
|
semaphore = xSemaphoreCreateBinary();
|
||||||
|
assert(semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
BinarySemaphoreFreeRTOS::~BinarySemaphoreFreeRTOS()
|
BinarySemaphoreFreeRTOS::~BinarySemaphoreFreeRTOS()
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "../freertosinc.h"
|
#include "../freertosinc.h"
|
||||||
|
|
||||||
namespace concurrency
|
namespace concurrency
|
||||||
@@ -28,4 +27,4 @@ class BinarySemaphoreFreeRTOS
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
} // namespace concurrency
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "../freertosinc.h"
|
#include "../freertosinc.h"
|
||||||
|
|
||||||
namespace concurrency
|
namespace concurrency
|
||||||
@@ -28,4 +27,4 @@ class BinarySemaphorePosix
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
} // namespace concurrency
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "NotifiedWorkerThread.h"
|
#include "NotifiedWorkerThread.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
namespace concurrency
|
namespace concurrency
|
||||||
@@ -28,6 +29,7 @@ IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
|
|||||||
if (overwrite || notification == 0) {
|
if (overwrite || notification == 0) {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
setInterval(0); // Run ASAP
|
setInterval(0); // Run ASAP
|
||||||
|
runASAP = true;
|
||||||
|
|
||||||
notification = v;
|
notification = v;
|
||||||
if (debugNotification)
|
if (debugNotification)
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#if defined(TBEAM_V10)
|
#if defined(TBEAM_V10)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "tbeam"
|
#define HW_VENDOR HardwareModel_TBEAM
|
||||||
|
|
||||||
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(TBEAM_V07)
|
#elif defined(TBEAM_V07)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "tbeam0.7"
|
#define HW_VENDOR HardwareModel_TBEAM0p7
|
||||||
|
|
||||||
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
|
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "heltec"
|
#define HW_VENDOR HardwareModel_HELTEC
|
||||||
|
|
||||||
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
|
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
|
||||||
// Tested on Neo6m module.
|
// Tested on Neo6m module.
|
||||||
@@ -258,7 +258,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(TLORA_V1)
|
#elif defined(TLORA_V1)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "tlora-v1"
|
#define HW_VENDOR HardwareModel_TLORA_V1
|
||||||
#undef GPS_RX_PIN
|
#undef GPS_RX_PIN
|
||||||
#undef GPS_TX_PIN
|
#undef GPS_TX_PIN
|
||||||
#define GPS_RX_PIN 36
|
#define GPS_RX_PIN 36
|
||||||
@@ -282,7 +282,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(TLORA_V2)
|
#elif defined(TLORA_V2)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "tlora-v2"
|
#define HW_VENDOR HardwareModel_TLORA_V2
|
||||||
|
|
||||||
#undef GPS_RX_PIN
|
#undef GPS_RX_PIN
|
||||||
#undef GPS_TX_PIN
|
#undef GPS_TX_PIN
|
||||||
@@ -311,7 +311,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(TLORA_V1_3)
|
#elif defined(TLORA_V1_3)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "tlora-v1-3"
|
#define HW_VENDOR HardwareModel_TLORA_V1_1p3
|
||||||
|
|
||||||
#undef GPS_RX_PIN
|
#undef GPS_RX_PIN
|
||||||
#undef GPS_TX_PIN
|
#undef GPS_TX_PIN
|
||||||
@@ -338,11 +338,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(TLORA_V2_1_16)
|
#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
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "tlora-v2-1-1.6"
|
#define HW_VENDOR HardwareModel_TLORA_V2_1_1p6
|
||||||
|
|
||||||
#undef GPS_RX_PIN
|
#undef GPS_RX_PIN
|
||||||
#undef GPS_TX_PIN
|
#undef GPS_TX_PIN
|
||||||
#define GPS_RX_PIN 36
|
#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 GPS_TX_PIN 13
|
||||||
|
|
||||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||||
@@ -366,7 +366,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(GENIEBLOCKS)
|
#elif defined(GENIEBLOCKS)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "genieblocks"
|
#define HW_VENDOR HardwareModel_GENIEBLOCKS
|
||||||
#undef GPS_RX_PIN
|
#undef GPS_RX_PIN
|
||||||
#undef GPS_TX_PIN
|
#undef GPS_TX_PIN
|
||||||
#define GPS_RX_PIN 5
|
#define GPS_RX_PIN 5
|
||||||
@@ -382,8 +382,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#define LED_PIN 12 // If defined we will blink this LED
|
#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 -->
|
//#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
|
// 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.
|
// pull-ups or pull-down resistors.
|
||||||
|
|
||||||
#define USE_RF95
|
#define USE_RF95
|
||||||
#define LORA_DIO0 38 // a No connect on the SX1262 module
|
#define LORA_DIO0 38 // a No connect on the SX1262 module
|
||||||
@@ -399,7 +399,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#ifdef ARDUINO_NRF52840_PCA10056
|
#ifdef ARDUINO_NRF52840_PCA10056
|
||||||
|
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR "nrf52dk"
|
#define HW_VENDOR HardwareModel_NRF52840DK
|
||||||
|
|
||||||
// This board uses 0 to be mean LED on
|
// This board uses 0 to be mean LED on
|
||||||
#undef LED_INVERTED
|
#undef LED_INVERTED
|
||||||
@@ -407,15 +407,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#elif defined(ARDUINO_NRF52840_PPR)
|
#elif defined(ARDUINO_NRF52840_PPR)
|
||||||
|
|
||||||
#define HW_VENDOR "ppr"
|
#define HW_VENDOR HardwareModel_PPR
|
||||||
|
|
||||||
#elif NRF52_SERIES
|
#elif NRF52_SERIES
|
||||||
|
|
||||||
#define HW_VENDOR "nrf52unknown" // FIXME - unknown nrf52 board
|
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN
|
||||||
|
|
||||||
#elif PORTDUINO
|
#elif PORTDUINO
|
||||||
|
|
||||||
#define HW_VENDOR "portduino"
|
#define HW_VENDOR HardwareModel_PORTDUINO
|
||||||
|
|
||||||
#define USE_SIM_RADIO
|
#define USE_SIM_RADIO
|
||||||
|
|
||||||
@@ -457,7 +457,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#include "SerialConsole.h"
|
#include "SerialConsole.h"
|
||||||
|
|
||||||
#define DEBUG_PORT console // Serial debug port
|
#define DEBUG_PORT (*console) // Serial debug port
|
||||||
|
|
||||||
// What platforms should use SEGGER?
|
// What platforms should use SEGGER?
|
||||||
#ifdef NRF52_SERIES
|
#ifdef NRF52_SERIES
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "../concurrency/LockGuard.h"
|
#include "../concurrency/LockGuard.h"
|
||||||
|
#include "../graphics/Screen.h"
|
||||||
|
#include "../main.h"
|
||||||
#include "BluetoothSoftwareUpdate.h"
|
#include "BluetoothSoftwareUpdate.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RadioLibInterface.h"
|
#include "RadioLibInterface.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "nimble/BluetoothUtil.h"
|
#include "nimble/BluetoothUtil.h"
|
||||||
#include "NodeDB.h"
|
|
||||||
#include "../graphics/Screen.h"
|
|
||||||
#include "../main.h"
|
|
||||||
|
|
||||||
#include <CRC32.h>
|
#include <CRC32.h>
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
int16_t updateResultHandle = -1;
|
int16_t updateResultHandle = -1;
|
||||||
|
|
||||||
static CRC32 crc;
|
static CRC32 crc;
|
||||||
static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
|
|
||||||
|
|
||||||
static uint32_t updateExpectedSize, updateActualSize;
|
static uint32_t updateExpectedSize, updateActualSize;
|
||||||
static uint8_t update_result;
|
static uint8_t update_result;
|
||||||
@@ -51,8 +50,8 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
|
|||||||
|
|
||||||
screen->startFirmwareUpdateScreen();
|
screen->startFirmwareUpdateScreen();
|
||||||
if (RadioLibInterface::instance)
|
if (RadioLibInterface::instance)
|
||||||
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are
|
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we
|
||||||
// writing flash - shut the radio off during updates
|
// are writing flash - shut the radio off during updates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
|
|||||||
crc.update(data, len);
|
crc.update(data, len);
|
||||||
Update.write(data, len);
|
Update.write(data, len);
|
||||||
updateActualSize += len;
|
updateActualSize += len;
|
||||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
powerFSM.trigger(EVENT_FIRMWARE_UPDATE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -107,8 +106,7 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble
|
|||||||
if (update_region == U_SPIFFS) {
|
if (update_region == U_SPIFFS) {
|
||||||
DEBUG_MSG("SPIFFS updated!\n");
|
DEBUG_MSG("SPIFFS updated!\n");
|
||||||
nodeDB.saveToDisk(); // Since we just wiped spiffs, we need to save our current state
|
nodeDB.saveToDisk(); // Since we just wiped spiffs, we need to save our current state
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
|
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
|
||||||
rebootAtMsec = millis() + 5000;
|
rebootAtMsec = millis() + 5000;
|
||||||
}
|
}
|
||||||
@@ -140,14 +138,6 @@ int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct bl
|
|||||||
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
|
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bluetoothRebootCheck()
|
|
||||||
{
|
|
||||||
if (rebootAtMsec && millis() > rebootAtMsec) {
|
|
||||||
DEBUG_MSG("Rebooting for update\n");
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
See bluetooth-api.md
|
See bluetooth-api.md
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
void reinitUpdateService();
|
void reinitUpdateService();
|
||||||
|
|
||||||
void bluetoothRebootCheck();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,9 +7,10 @@
|
|||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <Preferences.h>
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
#include <nvs.h>
|
#include <nvs.h>
|
||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
#include <driver/rtc_io.h>
|
|
||||||
|
|
||||||
void getMacAddr(uint8_t *dmac)
|
void getMacAddr(uint8_t *dmac)
|
||||||
{
|
{
|
||||||
@@ -45,6 +46,18 @@ void esp32Setup()
|
|||||||
DEBUG_MSG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d\n", nvs_stats.used_entries, nvs_stats.free_entries,
|
DEBUG_MSG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d\n", nvs_stats.used_entries, nvs_stats.free_entries,
|
||||||
nvs_stats.total_entries);
|
nvs_stats.total_entries);
|
||||||
|
|
||||||
|
DEBUG_MSG("Setup Preferences in Flash Storage\n");
|
||||||
|
|
||||||
|
// Create object to store our persistant data
|
||||||
|
Preferences preferences;
|
||||||
|
preferences.begin("meshtastic", false);
|
||||||
|
|
||||||
|
uint32_t rebootCounter = preferences.getUInt("rebootCounter", 0);
|
||||||
|
rebootCounter++;
|
||||||
|
preferences.putUInt("rebootCounter", rebootCounter);
|
||||||
|
preferences.end();
|
||||||
|
DEBUG_MSG("Number of Device Reboots: %d\n", rebootCounter);
|
||||||
|
|
||||||
// enableModemSleep();
|
// enableModemSleep();
|
||||||
|
|
||||||
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
|
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
|
||||||
@@ -84,7 +97,6 @@ void esp32Loop()
|
|||||||
{
|
{
|
||||||
esp_task_wdt_reset(); // service our app level watchdog
|
esp_task_wdt_reset(); // service our app level watchdog
|
||||||
loopBLE();
|
loopBLE();
|
||||||
bluetoothRebootCheck();
|
|
||||||
|
|
||||||
// for debug printing
|
// for debug printing
|
||||||
// radio.radioIf.canSleep();
|
// radio.radioIf.canSleep();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ uint8_t GPS::i2cAddress = 0;
|
|||||||
|
|
||||||
GPS *gps;
|
GPS *gps;
|
||||||
|
|
||||||
/// Multiple GPS instances might use the same serial port (in sequence), but we can
|
/// Multiple GPS instances might use the same serial port (in sequence), but we can
|
||||||
/// only init that port once.
|
/// only init that port once.
|
||||||
static bool didSerialInit;
|
static bool didSerialInit;
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ bool GPS::setupGPS()
|
|||||||
{
|
{
|
||||||
if (_serial_gps && !didSerialInit) {
|
if (_serial_gps && !didSerialInit) {
|
||||||
didSerialInit = true;
|
didSerialInit = true;
|
||||||
|
|
||||||
#ifdef GPS_RX_PIN
|
#ifdef GPS_RX_PIN
|
||||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||||
#else
|
#else
|
||||||
@@ -73,6 +73,13 @@ bool GPS::setup()
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPS::~GPS()
|
||||||
|
{
|
||||||
|
// we really should unregister our sleep observer
|
||||||
|
notifySleepObserver.unobserve();
|
||||||
|
notifyDeepSleepObserver.unobserve();
|
||||||
|
}
|
||||||
|
|
||||||
// Allow defining the polarity of the WAKE output. default is active high
|
// Allow defining the polarity of the WAKE output. default is active high
|
||||||
#ifndef GPS_WAKE_ACTIVE
|
#ifndef GPS_WAKE_ACTIVE
|
||||||
#define GPS_WAKE_ACTIVE 1
|
#define GPS_WAKE_ACTIVE 1
|
||||||
@@ -86,8 +93,8 @@ void GPS::wake()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPS::sleep()
|
||||||
void GPS::sleep() {
|
{
|
||||||
#ifdef PIN_GPS_WAKE
|
#ifdef PIN_GPS_WAKE
|
||||||
digitalWrite(PIN_GPS_WAKE, GPS_WAKE_ACTIVE ? 0 : 1);
|
digitalWrite(PIN_GPS_WAKE, GPS_WAKE_ACTIVE ? 0 : 1);
|
||||||
pinMode(PIN_GPS_WAKE, OUTPUT);
|
pinMode(PIN_GPS_WAKE, OUTPUT);
|
||||||
@@ -158,7 +165,8 @@ uint32_t GPS::getWakeTime() const
|
|||||||
return t; // already maxint
|
return t; // already maxint
|
||||||
|
|
||||||
if (t == 0)
|
if (t == 0)
|
||||||
t = radioConfig.preferences.is_router ? 5 * 60 : 15 * 60; // Allow up to 15 mins for each attempt (probably will be much less if we can find sats) or less if a router
|
t = radioConfig.preferences.is_router ? 5 * 60 : 15 * 60; // Allow up to 15 mins for each attempt (probably will be much
|
||||||
|
// less if we can find sats) or less if a router
|
||||||
|
|
||||||
t *= 1000; // msecs
|
t *= 1000; // msecs
|
||||||
|
|
||||||
@@ -179,8 +187,8 @@ uint32_t GPS::getSleepTime() const
|
|||||||
if (t == UINT32_MAX)
|
if (t == UINT32_MAX)
|
||||||
return t; // already maxint
|
return t; // already maxint
|
||||||
|
|
||||||
if (t == 0) // default - unset in preferences
|
if (t == 0) // default - unset in preferences
|
||||||
t = radioConfig.preferences.is_router ? 24 * 60 * 60 : 2 * 60; // 2 mins or once per day for routers
|
t = radioConfig.preferences.is_router ? 24 * 60 * 60 : 2 * 60; // 2 mins or once per day for routers
|
||||||
|
|
||||||
t *= 1000;
|
t *= 1000;
|
||||||
|
|
||||||
@@ -300,3 +308,49 @@ int GPS::prepareDeepSleep(void *unused)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef GPS_TX_PIN
|
||||||
|
#include "UBloxGPS.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_AIR530_GPS
|
||||||
|
#include "Air530GPS.h"
|
||||||
|
#elif !defined(NO_GPS)
|
||||||
|
#include "NMEAGPS.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
GPS* createGps() {
|
||||||
|
|
||||||
|
#ifdef NO_GPS
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
|
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
||||||
|
#ifdef GPS_TX_PIN
|
||||||
|
// Init GPS - first try ublox
|
||||||
|
UBloxGPS *ublox = new UBloxGPS();
|
||||||
|
|
||||||
|
if (!ublox->setup()) {
|
||||||
|
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
||||||
|
delete ublox;
|
||||||
|
ublox = NULL;
|
||||||
|
} else {
|
||||||
|
return ublox;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (GPS::_serial_gps) {
|
||||||
|
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||||
|
// assume NMEA at 9600 baud.
|
||||||
|
DEBUG_MSG("Hoping that NMEA might work\n");
|
||||||
|
#ifdef HAS_AIR530_GPS
|
||||||
|
GPS* new_gps = new Air530GPS();
|
||||||
|
#else
|
||||||
|
GPS* new_gps = new NMEAGPS();
|
||||||
|
#endif
|
||||||
|
new_gps->setup();
|
||||||
|
return new_gps;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -47,7 +47,7 @@ class GPS : private concurrency::OSThread
|
|||||||
|
|
||||||
GPS() : concurrency::OSThread("GPS") {}
|
GPS() : concurrency::OSThread("GPS") {}
|
||||||
|
|
||||||
virtual ~GPS() {} // FIXME, we really should unregister our sleep observer
|
virtual ~GPS();
|
||||||
|
|
||||||
/** We will notify this observable anytime GPS state has changed meaningfully */
|
/** We will notify this observable anytime GPS state has changed meaningfully */
|
||||||
Observable<const meshtastic::GPSStatus *> newStatus;
|
Observable<const meshtastic::GPSStatus *> newStatus;
|
||||||
@@ -71,6 +71,9 @@ class GPS : private concurrency::OSThread
|
|||||||
* */
|
* */
|
||||||
void forceWake(bool on);
|
void forceWake(bool on);
|
||||||
|
|
||||||
|
// Some GPS modules (ublock) require factory reset
|
||||||
|
virtual bool factoryReset() { return true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Do gps chipset specific init, return true for success
|
/// Do gps chipset specific init, return true for success
|
||||||
virtual bool setupGPS();
|
virtual bool setupGPS();
|
||||||
@@ -145,4 +148,8 @@ class GPS : private concurrency::OSThread
|
|||||||
virtual int32_t runOnce();
|
virtual int32_t runOnce();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Creates an instance of the GPS class.
|
||||||
|
// Returns the new instance or null if the GPS is not present.
|
||||||
|
GPS* createGps();
|
||||||
|
|
||||||
extern GPS *gps;
|
extern GPS *gps;
|
||||||
|
|||||||
@@ -39,22 +39,23 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
|||||||
currentQuality = q;
|
currentQuality = q;
|
||||||
shouldSet = true;
|
shouldSet = true;
|
||||||
DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
|
DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
|
||||||
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) {
|
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
|
||||||
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
|
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
|
||||||
shouldSet = true;
|
shouldSet = true;
|
||||||
DEBUG_MSG("Reapplying GPS time to correct clock drift %ld secs\n", tv->tv_sec);
|
DEBUG_MSG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
shouldSet = false;
|
shouldSet = false;
|
||||||
|
|
||||||
if (shouldSet) {
|
if (shouldSet) {
|
||||||
lastSetMsec = now;
|
lastSetMsec = now;
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
settimeofday(tv, NULL);
|
settimeofday(tv, NULL);
|
||||||
#else
|
|
||||||
DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n");
|
|
||||||
#endif
|
|
||||||
readFromRTC();
|
readFromRTC();
|
||||||
|
#else
|
||||||
|
timeStartMsec = now;
|
||||||
|
zeroOffsetSecs = tv->tv_sec;
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -27,4 +27,8 @@ uint32_t getTime();
|
|||||||
/// Return time since 1970 in secs. If quality is RTCQualityNone return zero
|
/// Return time since 1970 in secs. If quality is RTCQualityNone return zero
|
||||||
uint32_t getValidTime(RTCQuality minQuality);
|
uint32_t getValidTime(RTCQuality minQuality);
|
||||||
|
|
||||||
void readFromRTC();
|
void readFromRTC();
|
||||||
|
|
||||||
|
#define SEC_PER_DAY 86400
|
||||||
|
#define SEC_PER_HOUR 3600
|
||||||
|
#define SEC_PER_MIN 60
|
||||||
@@ -28,11 +28,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
|
#include "gps/RTC.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "plugins/TextMessagePlugin.h"
|
|
||||||
#include "mesh/Channels.h"
|
#include "mesh/Channels.h"
|
||||||
|
#include "plugins/TextMessagePlugin.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -143,34 +144,34 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
drawIconScreen(region, display, state, x, y);
|
drawIconScreen(region, display, state, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_EINK
|
||||||
/// Used on eink displays while in deep sleep
|
/// Used on eink displays while in deep sleep
|
||||||
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
drawIconScreen("Sleeping...", display, state, x, y);
|
drawIconScreen("Sleeping...", display, state, x, y);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
uint8_t plugin_frame;
|
uint8_t plugin_frame;
|
||||||
// there's a little but in the UI transition code
|
// there's a little but in the UI transition code
|
||||||
// where it invokes the function at the correct offset
|
// where it invokes the function at the correct offset
|
||||||
// in the array of "drawScreen" functions; however,
|
// in the array of "drawScreen" functions; however,
|
||||||
// the passed-state doesn't quite reflect the "current"
|
// the passed-state doesn't quite reflect the "current"
|
||||||
// screen, so we have to detect it.
|
// screen, so we have to detect it.
|
||||||
if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) {
|
if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) {
|
||||||
// if we're transitioning from the end of the frame list back around to the first
|
// if we're transitioning from the end of the frame list back around to the first
|
||||||
// frame, then we want this to be `0`
|
// frame, then we want this to be `0`
|
||||||
plugin_frame = state->transitionFrameTarget;
|
plugin_frame = state->transitionFrameTarget;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// otherwise, just display the plugin frame that's aligned with the current frame
|
// otherwise, just display the plugin frame that's aligned with the current frame
|
||||||
plugin_frame = state->currentFrame;
|
plugin_frame = state->currentFrame;
|
||||||
//DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
|
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
|
||||||
}
|
}
|
||||||
//DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
|
// DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
|
||||||
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
|
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
|
||||||
pi.drawFrame(display,state,x,y);
|
pi.drawFrame(display, state, x, y);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
@@ -202,11 +203,10 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait...");
|
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait...");
|
||||||
|
|
||||||
//display->setFont(FONT_LARGE);
|
// display->setFont(FONT_LARGE);
|
||||||
//display->drawString(64 + x, 26 + y, btPIN);
|
// display->drawString(64 + x, 26 + y, btPIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Draw the last text message we received
|
/// Draw the last text message we received
|
||||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
@@ -717,6 +717,7 @@ void Screen::handleSetOn(bool on)
|
|||||||
dispdev.displayOn();
|
dispdev.displayOn();
|
||||||
enabled = true;
|
enabled = true;
|
||||||
setInterval(0); // Draw ASAP
|
setInterval(0); // Draw ASAP
|
||||||
|
runASAP = true;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("Turning off screen\n");
|
DEBUG_MSG("Turning off screen\n");
|
||||||
dispdev.displayOff();
|
dispdev.displayOff();
|
||||||
@@ -791,7 +792,8 @@ void Screen::setup()
|
|||||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||||
textMessageObserver.observe(textMessagePlugin);
|
if (textMessagePlugin)
|
||||||
|
textMessageObserver.observe(textMessagePlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::forceDisplay()
|
void Screen::forceDisplay()
|
||||||
@@ -839,7 +841,7 @@ int32_t Screen::runOnce()
|
|||||||
break;
|
break;
|
||||||
case Cmd::START_FIRMWARE_UPDATE_SCREEN:
|
case Cmd::START_FIRMWARE_UPDATE_SCREEN:
|
||||||
handleStartFirmwareUpdateScreen();
|
handleStartFirmwareUpdateScreen();
|
||||||
break;
|
break;
|
||||||
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
|
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
|
||||||
case Cmd::STOP_BOOT_SCREEN:
|
case Cmd::STOP_BOOT_SCREEN:
|
||||||
setFrames();
|
setFrames();
|
||||||
@@ -849,7 +851,7 @@ int32_t Screen::runOnce()
|
|||||||
free(cmd.print_text);
|
free(cmd.print_text);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUG_MSG("BUG: invalid cmd");
|
DEBUG_MSG("BUG: invalid cmd\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -933,7 +935,7 @@ void Screen::setFrames()
|
|||||||
for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) {
|
for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) {
|
||||||
normalFrames[numframes++] = drawPluginFrame;
|
normalFrames[numframes++] = drawPluginFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
|
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
|
||||||
|
|
||||||
// If we have a critical fault, show it first
|
// If we have a critical fault, show it first
|
||||||
@@ -1052,6 +1054,7 @@ void Screen::setFastFramerate()
|
|||||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||||
ui.setTargetFPS(targetFramerate);
|
ui.setTargetFPS(targetFramerate);
|
||||||
setInterval(0); // redraw ASAP
|
setInterval(0); // redraw ASAP
|
||||||
|
runASAP = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
@@ -1283,14 +1286,41 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
|||||||
uint32_t minutes = seconds / 60;
|
uint32_t minutes = seconds / 60;
|
||||||
uint32_t hours = minutes / 60;
|
uint32_t hours = minutes / 60;
|
||||||
uint32_t days = hours / 24;
|
uint32_t days = hours / 24;
|
||||||
currentMillis %= 1000;
|
// currentMillis %= 1000;
|
||||||
seconds %= 60;
|
// seconds %= 60;
|
||||||
minutes %= 60;
|
// minutes %= 60;
|
||||||
hours %= 24;
|
// hours %= 24;
|
||||||
|
|
||||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
|
// Show uptime as days, hours, minutes OR seconds
|
||||||
String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
|
String uptime;
|
||||||
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
|
if (days >= 2)
|
||||||
|
uptime += String(days) + "d ";
|
||||||
|
else if (hours >= 2)
|
||||||
|
uptime += String(hours) + "h ";
|
||||||
|
else if (minutes >= 1)
|
||||||
|
uptime += String(minutes) + "m ";
|
||||||
|
else
|
||||||
|
uptime += String(seconds) + "s ";
|
||||||
|
|
||||||
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
|
||||||
|
if (rtc_sec > 0) {
|
||||||
|
long hms = rtc_sec % SEC_PER_DAY;
|
||||||
|
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||||||
|
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
|
||||||
|
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
|
||||||
|
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||||||
|
|
||||||
|
// Tear apart hms into h:m:s
|
||||||
|
int hour = hms / SEC_PER_HOUR;
|
||||||
|
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||||
|
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||||||
|
|
||||||
|
char timebuf[9];
|
||||||
|
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", hour, min, sec);
|
||||||
|
uptime += timebuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, uptime);
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
// Show CPU Frequency.
|
// Show CPU Frequency.
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef NO_SCREEN
|
||||||
|
namespace graphics
|
||||||
|
{
|
||||||
|
// Noop class for boards without screen.
|
||||||
|
class Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Screen(char){}
|
||||||
|
void onPress() {}
|
||||||
|
void setup() {}
|
||||||
|
void setOn(bool) {}
|
||||||
|
void print(const char*){}
|
||||||
|
void adjustBrightness(){}
|
||||||
|
void doDeepSleep() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include <OLEDDisplayUi.h>
|
#include <OLEDDisplayUi.h>
|
||||||
@@ -278,3 +296,4 @@ class Screen : public concurrency::OSThread
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
#endif
|
||||||
121
src/main.cpp
121
src/main.cpp
@@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
#include "Air530GPS.h"
|
#include "GPS.h"
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "UBloxGPS.h"
|
|
||||||
#include "airtime.h"
|
#include "airtime.h"
|
||||||
|
#include "buzz.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
@@ -32,6 +32,10 @@
|
|||||||
#include "nimble/BluetoothUtil.h"
|
#include "nimble/BluetoothUtil.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PORTDUINO
|
||||||
|
#include "mesh/wifi/WiFiServerAPI.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "RF95Interface.h"
|
#include "RF95Interface.h"
|
||||||
#include "SX1262Interface.h"
|
#include "SX1262Interface.h"
|
||||||
|
|
||||||
@@ -63,7 +67,7 @@ Router *router = NULL; // Users of router don't care what sort of subclass imple
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Application
|
// Application
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
#ifndef NO_WIRE
|
||||||
void scanI2Cdevice(void)
|
void scanI2Cdevice(void)
|
||||||
{
|
{
|
||||||
byte err, addr;
|
byte err, addr;
|
||||||
@@ -100,6 +104,9 @@ void scanI2Cdevice(void)
|
|||||||
else
|
else
|
||||||
DEBUG_MSG("done\n");
|
DEBUG_MSG("done\n");
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
void scanI2Cdevice(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *getDeviceName()
|
const char *getDeviceName()
|
||||||
{
|
{
|
||||||
@@ -169,6 +176,7 @@ class ButtonThread : public OSThread
|
|||||||
#ifdef BUTTON_PIN_ALT
|
#ifdef BUTTON_PIN_ALT
|
||||||
OneButton userButtonAlt;
|
OneButton userButtonAlt;
|
||||||
#endif
|
#endif
|
||||||
|
static bool shutdown_on_long_stop;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static uint32_t longPressTime;
|
static uint32_t longPressTime;
|
||||||
@@ -235,13 +243,23 @@ class ButtonThread : public OSThread
|
|||||||
// DEBUG_MSG("Long press!\n");
|
// DEBUG_MSG("Long press!\n");
|
||||||
screen->adjustBrightness();
|
screen->adjustBrightness();
|
||||||
|
|
||||||
// If user button is held down for 10 seconds, shutdown the device.
|
// If user button is held down for 5 seconds, shutdown the device.
|
||||||
if (millis() - longPressTime > 10 * 1000) {
|
if (millis() - longPressTime > 5 * 1000) {
|
||||||
#ifdef TBEAM_V10
|
#ifdef TBEAM_V10
|
||||||
if (axp192_found == true) {
|
if (axp192_found == true) {
|
||||||
setLed(false);
|
setLed(false);
|
||||||
power->shutdown();
|
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
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
|
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
|
||||||
@@ -265,9 +283,15 @@ class ButtonThread : public OSThread
|
|||||||
{
|
{
|
||||||
DEBUG_MSG("Long press stop!\n");
|
DEBUG_MSG("Long press stop!\n");
|
||||||
longPressTime = 0;
|
longPressTime = 0;
|
||||||
|
if (shutdown_on_long_stop) {
|
||||||
|
playShutdownMelody();
|
||||||
|
power->shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool ButtonThread::shutdown_on_long_stop = false;
|
||||||
|
|
||||||
static Periodic *ledPeriodic;
|
static Periodic *ledPeriodic;
|
||||||
static OSThread *powerFSMthread, *buttonThread;
|
static OSThread *powerFSMthread, *buttonThread;
|
||||||
uint32_t ButtonThread::longPressTime = 0;
|
uint32_t ButtonThread::longPressTime = 0;
|
||||||
@@ -279,16 +303,23 @@ void setup()
|
|||||||
concurrency::hasBeenSetup = true;
|
concurrency::hasBeenSetup = true;
|
||||||
|
|
||||||
#ifdef SEGGER_STDOUT_CH
|
#ifdef SEGGER_STDOUT_CH
|
||||||
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM;
|
||||||
|
#ifdef NRF52840_XXAA
|
||||||
|
auto buflen = 4096; // this board has a fair amount of ram
|
||||||
|
#else
|
||||||
|
auto buflen = 256; // this board has a fair amount of ram
|
||||||
|
#endif
|
||||||
|
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, buflen, mode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SEGGER
|
#ifdef USE_SEGGER
|
||||||
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Debug
|
|
||||||
#ifdef DEBUG_PORT
|
#ifdef DEBUG_PORT
|
||||||
DEBUG_PORT.init(); // Set serial baud rate and init our mesh console
|
if (!radioConfig.preferences.serial_disabled) {
|
||||||
|
consoleInit(); // Set serial baud rate and init our mesh console
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
initDeepSleep();
|
initDeepSleep();
|
||||||
@@ -335,7 +366,7 @@ void setup()
|
|||||||
|
|
||||||
#ifdef I2C_SDA
|
#ifdef I2C_SDA
|
||||||
Wire.begin(I2C_SDA, I2C_SCL);
|
Wire.begin(I2C_SDA, I2C_SCL);
|
||||||
#else
|
#elif !defined(NO_WIRE)
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -359,7 +390,7 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Hello
|
// Hello
|
||||||
DEBUG_MSG("Meshtastic hwvendor=%s, swver=%s, hwver=%s\n", HW_VENDOR, optstr(APP_VERSION), optstr(HW_VERSION));
|
DEBUG_MSG("Meshtastic hwvendor=%d, swver=%s, hwver=%s\n", HW_VENDOR, optstr(APP_VERSION), optstr(HW_VERSION));
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
// Don't init display if we don't have one or we are waking headless due to a timer event
|
// Don't init display if we don't have one or we are waking headless due to a timer event
|
||||||
@@ -372,7 +403,7 @@ void setup()
|
|||||||
#ifdef NRF52_SERIES
|
#ifdef NRF52_SERIES
|
||||||
nrf52Setup();
|
nrf52Setup();
|
||||||
#endif
|
#endif
|
||||||
|
playStartMelody();
|
||||||
// We do this as early as possible because this loads preferences from flash
|
// We do this as early as possible because this loads preferences from flash
|
||||||
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
|
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
|
||||||
nodeDB.init();
|
nodeDB.init();
|
||||||
@@ -410,34 +441,7 @@ void setup()
|
|||||||
pinMode(BATTERY_EN_PIN, OUTPUT);
|
pinMode(BATTERY_EN_PIN, OUTPUT);
|
||||||
digitalWrite(BATTERY_EN_PIN, LOW);
|
digitalWrite(BATTERY_EN_PIN, LOW);
|
||||||
#endif
|
#endif
|
||||||
|
gps = createGps();
|
||||||
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
|
||||||
UBloxGPS *ublox = NULL;
|
|
||||||
#ifdef GPS_TX_PIN
|
|
||||||
// Init GPS - first try ublox
|
|
||||||
ublox = new UBloxGPS();
|
|
||||||
gps = ublox;
|
|
||||||
if (!gps->setup()) {
|
|
||||||
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
|
||||||
|
|
||||||
delete ublox;
|
|
||||||
gps = ublox = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!gps && GPS::_serial_gps) {
|
|
||||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
|
||||||
// assume NMEA at 9600 baud.
|
|
||||||
// dumb NMEA access only work for serial GPSes)
|
|
||||||
DEBUG_MSG("Hoping that NMEA might work\n");
|
|
||||||
|
|
||||||
#ifdef HAS_AIR530_GPS
|
|
||||||
gps = new Air530GPS();
|
|
||||||
#else
|
|
||||||
gps = new NMEAGPS();
|
|
||||||
#endif
|
|
||||||
gps->setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gps)
|
if (gps)
|
||||||
gpsStatus->observe(&gps->newStatus);
|
gpsStatus->observe(&gps->newStatus);
|
||||||
@@ -471,8 +475,8 @@ void setup()
|
|||||||
// We have now loaded our saved preferences from flash
|
// We have now loaded our saved preferences from flash
|
||||||
|
|
||||||
// ONCE we will factory reset the GPS for bug #327
|
// ONCE we will factory reset the GPS for bug #327
|
||||||
if (ublox && !devicestate.did_gps_reset) {
|
if (gps && !devicestate.did_gps_reset) {
|
||||||
if (ublox->factoryReset()) { // If we don't succeed try again next time
|
if (gps->factoryReset()) { // If we don't succeed try again next time
|
||||||
devicestate.did_gps_reset = true;
|
devicestate.did_gps_reset = true;
|
||||||
nodeDB.saveToDisk();
|
nodeDB.saveToDisk();
|
||||||
}
|
}
|
||||||
@@ -533,6 +537,10 @@ void setup()
|
|||||||
webServerThread = new WebServerThread();
|
webServerThread = new WebServerThread();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PORTDUINO
|
||||||
|
initApiServer();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Start airtime logger thread.
|
// Start airtime logger thread.
|
||||||
airTime = new AirTime();
|
airTime = new AirTime();
|
||||||
|
|
||||||
@@ -570,19 +578,39 @@ Periodic axpDebugOutput(axpDebugRead);
|
|||||||
axpDebugOutput.setup();
|
axpDebugOutput.setup();
|
||||||
#endif
|
#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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
bool runASAP;
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// axpDebugOutput.loop();
|
runASAP = false;
|
||||||
|
|
||||||
#ifdef DEBUG_PORT
|
// axpDebugOutput.loop();
|
||||||
DEBUG_PORT.loop(); // Send/receive protobufs over the serial port
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
|
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
esp32Loop();
|
esp32Loop();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NRF52_SERIES
|
||||||
|
nrf52Loop();
|
||||||
|
#endif
|
||||||
|
rebootCheck();
|
||||||
|
|
||||||
// For debugging
|
// For debugging
|
||||||
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
|
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
|
||||||
@@ -607,6 +635,7 @@ void loop()
|
|||||||
mainController.nextThread->tillRun(millis())); */
|
mainController.nextThread->tillRun(millis())); */
|
||||||
|
|
||||||
// We want to sleep as long as possible here - because it saves power
|
// We want to sleep as long as possible here - because it saves power
|
||||||
mainDelay.delay(delayMsec);
|
if (!runASAP)
|
||||||
|
mainDelay.delay(delayMsec);
|
||||||
// if (didWake) DEBUG_MSG("wake!\n");
|
// if (didWake) DEBUG_MSG("wake!\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,4 +20,10 @@ extern graphics::Screen *screen;
|
|||||||
// Return a human readable string of the form "Meshtastic_ab13"
|
// Return a human readable string of the form "Meshtastic_ab13"
|
||||||
const char *getDeviceName();
|
const char *getDeviceName();
|
||||||
|
|
||||||
|
extern uint32_t rebootAtMsec;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|||||||
318
src/memtest.cpp
Normal file
318
src/memtest.cpp
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* mtest - Perform a memory test
|
||||||
|
*
|
||||||
|
* (C) Copyright 2000
|
||||||
|
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||||
|
*
|
||||||
|
* See file CREDITS for list of people who contributed to this
|
||||||
|
* project.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
|
* MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform a memory test. A more complete alternative test can be
|
||||||
|
* configured using CONFIG_CMD_MTEST_ALTERNATIVE. The complete test
|
||||||
|
* loops until interrupted by ctrl-c or by a failure of one of the
|
||||||
|
* sub-tests.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_CMD_MTEST_ALTERNATIVE
|
||||||
|
static int mem_test(uint32_t _start, uint32_t _end, uint32_t pattern_unused)
|
||||||
|
{
|
||||||
|
volatile uint32_t *start = (volatile uint32_t *)_start;
|
||||||
|
volatile uint32_t *end = (volatile uint32_t *)_end;
|
||||||
|
volatile uint32_t *addr;
|
||||||
|
uint32_t val;
|
||||||
|
uint32_t readback;
|
||||||
|
vu_long addr_mask;
|
||||||
|
vu_long offset;
|
||||||
|
vu_long test_offset;
|
||||||
|
vu_long pattern;
|
||||||
|
vu_long temp;
|
||||||
|
vu_long anti_pattern;
|
||||||
|
vu_long num_words;
|
||||||
|
#ifdef CFG_MEMTEST_SCRATCH
|
||||||
|
volatile uint32_t *dummy = (vu_long *)CFG_MEMTEST_SCRATCH;
|
||||||
|
#else
|
||||||
|
volatile uint32_t *dummy = start;
|
||||||
|
#endif
|
||||||
|
int j;
|
||||||
|
int iterations = 1;
|
||||||
|
static const uint32_t bitpattern[] = {
|
||||||
|
0x00000001, /* single bit */
|
||||||
|
0x00000003, /* two adjacent bits */
|
||||||
|
0x00000007, /* three adjacent bits */
|
||||||
|
0x0000000F, /* four adjacent bits */
|
||||||
|
0x00000005, /* two non-adjacent bits */
|
||||||
|
0x00000015, /* three non-adjacent bits */
|
||||||
|
0x00000055, /* four non-adjacent bits */
|
||||||
|
0xaaaaaaaa, /* alternating 1/0 */
|
||||||
|
};
|
||||||
|
/* XXX: enforce alignment of start and end? */
|
||||||
|
for (;;) {
|
||||||
|
if (ctrlc()) {
|
||||||
|
putchar('\n');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("Iteration: %6d\r", iterations);
|
||||||
|
iterations++;
|
||||||
|
/*
|
||||||
|
* Data line test: write a pattern to the first
|
||||||
|
* location, write the 1's complement to a 'parking'
|
||||||
|
* address (changes the state of the data bus so a
|
||||||
|
* floating bus doen't give a false OK), and then
|
||||||
|
* read the value back. Note that we read it back
|
||||||
|
* into a variable because the next time we read it,
|
||||||
|
* it might be right (been there, tough to explain to
|
||||||
|
* the quality guys why it prints a failure when the
|
||||||
|
* "is" and "should be" are obviously the same in the
|
||||||
|
* error message).
|
||||||
|
*
|
||||||
|
* Rather than exhaustively testing, we test some
|
||||||
|
* patterns by shifting '1' bits through a field of
|
||||||
|
* '0's and '0' bits through a field of '1's (i.e.
|
||||||
|
* pattern and ~pattern).
|
||||||
|
*/
|
||||||
|
addr = start;
|
||||||
|
/* XXX */
|
||||||
|
if (addr == dummy)
|
||||||
|
++addr;
|
||||||
|
for (j = 0; j < sizeof(bitpattern) / sizeof(bitpattern[0]); j++) {
|
||||||
|
val = bitpattern[j];
|
||||||
|
for (; val != 0; val <<= 1) {
|
||||||
|
*addr = val;
|
||||||
|
*dummy = ~val; /* clear the test data off of the bus */
|
||||||
|
readback = *addr;
|
||||||
|
if (readback != val) {
|
||||||
|
printf("FAILURE (data line): "
|
||||||
|
"expected 0x%08lx, actual 0x%08lx at address 0x%p\n",
|
||||||
|
val, readback, addr);
|
||||||
|
}
|
||||||
|
*addr = ~val;
|
||||||
|
*dummy = val;
|
||||||
|
readback = *addr;
|
||||||
|
if (readback != ~val) {
|
||||||
|
printf("FAILURE (data line): "
|
||||||
|
"Is 0x%08lx, should be 0x%08lx at address 0x%p\n",
|
||||||
|
readback, ~val, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Based on code whose Original Author and Copyright
|
||||||
|
* information follows: Copyright (c) 1998 by Michael
|
||||||
|
* Barr. This software is placed into the public
|
||||||
|
* domain and may be used for any purpose. However,
|
||||||
|
* this notice must not be changed or removed and no
|
||||||
|
* warranty is either expressed or implied by its
|
||||||
|
* publication or distribution.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Address line test
|
||||||
|
*
|
||||||
|
* Description: Test the address bus wiring in a
|
||||||
|
* memory region by performing a walking
|
||||||
|
* 1's test on the relevant bits of the
|
||||||
|
* address and checking for aliasing.
|
||||||
|
* This test will find single-bit
|
||||||
|
* address failures such as stuck -high,
|
||||||
|
* stuck-low, and shorted pins. The base
|
||||||
|
* address and size of the region are
|
||||||
|
* selected by the caller.
|
||||||
|
*
|
||||||
|
* Notes: For best results, the selected base
|
||||||
|
* address should have enough LSB 0's to
|
||||||
|
* guarantee single address bit changes.
|
||||||
|
* For example, to test a 64-Kbyte
|
||||||
|
* region, select a base address on a
|
||||||
|
* 64-Kbyte boundary. Also, select the
|
||||||
|
* region size as a power-of-two if at
|
||||||
|
* all possible.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the test succeeds, 1 if the test fails.
|
||||||
|
*
|
||||||
|
* ## NOTE ## Be sure to specify start and end
|
||||||
|
* addresses such that addr_mask has
|
||||||
|
* lots of bits set. For example an
|
||||||
|
* address range of 01000000 02000000 is
|
||||||
|
* bad while a range of 01000000
|
||||||
|
* 01ffffff is perfect.
|
||||||
|
*/
|
||||||
|
addr_mask = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long);
|
||||||
|
pattern = (vu_long)0xaaaaaaaa;
|
||||||
|
anti_pattern = (vu_long)0x55555555;
|
||||||
|
debug("%s:%d: addr mask = 0x%.8lx\n", __FUNCTION__, __LINE__, addr_mask);
|
||||||
|
/*
|
||||||
|
* Write the default pattern at each of the
|
||||||
|
* power-of-two offsets.
|
||||||
|
*/
|
||||||
|
for (offset = 1; (offset & addr_mask) != 0; offset <<= 1)
|
||||||
|
start[offset] = pattern;
|
||||||
|
/*
|
||||||
|
* Check for address bits stuck high.
|
||||||
|
*/
|
||||||
|
test_offset = 0;
|
||||||
|
start[test_offset] = anti_pattern;
|
||||||
|
for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
|
||||||
|
temp = start[offset];
|
||||||
|
if (temp != pattern) {
|
||||||
|
printf("\nFAILURE: Address bit stuck high @ 0x%.8lx:"
|
||||||
|
" expected 0x%.8lx, actual 0x%.8lx\n",
|
||||||
|
(uint32_t)&start[offset], pattern, temp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start[test_offset] = pattern;
|
||||||
|
/*
|
||||||
|
* Check for addr bits stuck low or shorted.
|
||||||
|
*/
|
||||||
|
for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) {
|
||||||
|
start[test_offset] = anti_pattern;
|
||||||
|
for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
|
||||||
|
temp = start[offset];
|
||||||
|
if ((temp != pattern) && (offset != test_offset)) {
|
||||||
|
printf("\nFAILURE: Address bit stuck low or shorted @"
|
||||||
|
" 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n",
|
||||||
|
(uint32_t)&start[offset], pattern, temp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start[test_offset] = pattern;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Description: Test the integrity of a physical
|
||||||
|
* memory device by performing an
|
||||||
|
* increment/decrement test over the
|
||||||
|
* entire region. In the process every
|
||||||
|
* storage bit in the device is tested
|
||||||
|
* as a zero and a one. The base address
|
||||||
|
* and the size of the region are
|
||||||
|
* selected by the caller.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the test succeeds, 1 if the test fails.
|
||||||
|
*/
|
||||||
|
num_words = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long) + 1;
|
||||||
|
/*
|
||||||
|
* Fill memory with a known pattern.
|
||||||
|
*/
|
||||||
|
for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
|
||||||
|
start[offset] = pattern;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check each location and invert it for the second pass.
|
||||||
|
*/
|
||||||
|
for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
|
||||||
|
temp = start[offset];
|
||||||
|
if (temp != pattern) {
|
||||||
|
printf("\nFAILURE (read/write) @ 0x%.8lx:"
|
||||||
|
" expected 0x%.8lx, actual 0x%.8lx)\n",
|
||||||
|
(uint32_t)&start[offset], pattern, temp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
anti_pattern = ~pattern;
|
||||||
|
start[offset] = anti_pattern;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check each location for the inverted pattern and zero it.
|
||||||
|
*/
|
||||||
|
for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
|
||||||
|
anti_pattern = ~pattern;
|
||||||
|
temp = start[offset];
|
||||||
|
if (temp != anti_pattern) {
|
||||||
|
printf("\nFAILURE (read/write): @ 0x%.8lx:"
|
||||||
|
" expected 0x%.8lx, actual 0x%.8lx)\n",
|
||||||
|
(uint32_t)&start[offset], anti_pattern, temp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
start[offset] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int mem_test(uint32_t *_start, size_t len, bool doRead = true, bool doWrite = true)
|
||||||
|
{
|
||||||
|
volatile uint32_t *addr;
|
||||||
|
volatile uint32_t *start = (volatile uint32_t *)_start;
|
||||||
|
volatile uint32_t *end = start + len / sizeof(uint32_t);
|
||||||
|
uint32_t pattern = 0;
|
||||||
|
uint32_t val;
|
||||||
|
uint32_t readback;
|
||||||
|
uint32_t incr;
|
||||||
|
int rcode = 0;
|
||||||
|
incr = 1;
|
||||||
|
|
||||||
|
//DEBUG_MSG("memtest read=%d, write=%d\n", doRead, doWrite);
|
||||||
|
|
||||||
|
if (doWrite) {
|
||||||
|
//DEBUG_MSG("writing\n");
|
||||||
|
for (addr = start, val = pattern; addr < end; addr++) {
|
||||||
|
*addr = val;
|
||||||
|
val += incr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doRead) {
|
||||||
|
//DEBUG_MSG("reading\n");
|
||||||
|
for (addr = start, val = pattern; addr < end; addr++) {
|
||||||
|
readback = *addr;
|
||||||
|
if (readback != val) {
|
||||||
|
DEBUG_MSG("Mem error @ 0x%08X: "
|
||||||
|
"found 0x%08lX, expected 0x%08lX\n",
|
||||||
|
addr, readback, val);
|
||||||
|
rcode++;
|
||||||
|
}
|
||||||
|
val += incr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* Flip the pattern each time to make lots of zeros and
|
||||||
|
* then, the next time, lots of ones. We decrement
|
||||||
|
* the "negative" patterns and increment the "positive"
|
||||||
|
* patterns to preserve this feature.
|
||||||
|
*/
|
||||||
|
if(pattern & 0x80000000) {
|
||||||
|
pattern = -pattern; /* complement & increment */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pattern = ~pattern;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TESTBUF_LEN 16384
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
void doMemTest()
|
||||||
|
{
|
||||||
|
static uint32_t *testBuf;
|
||||||
|
static int iter;
|
||||||
|
|
||||||
|
if (!testBuf)
|
||||||
|
testBuf = (uint32_t *)malloc(TESTBUF_LEN);
|
||||||
|
|
||||||
|
assert(testBuf);
|
||||||
|
if (mem_test(testBuf, TESTBUF_LEN, iter % 2 == 1, iter % 2 == 0) > 0)
|
||||||
|
assert(0); // FIXME report error better
|
||||||
|
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
@@ -10,10 +10,14 @@ static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0
|
|||||||
|
|
||||||
Channels channels;
|
Channels channels;
|
||||||
|
|
||||||
|
const char *Channels::adminChannel = "admin";
|
||||||
|
const char *Channels::gpioChannel = "gpio";
|
||||||
|
const char *Channels::serialChannel = "serial";
|
||||||
|
|
||||||
uint8_t xorHash(const uint8_t *p, size_t len)
|
uint8_t xorHash(const uint8_t *p, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t code = 0;
|
uint8_t code = 0;
|
||||||
for (int i = 0; i < len; i++)
|
for (size_t i = 0; i < len; i++)
|
||||||
code ^= p[i];
|
code ^= p[i];
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@@ -29,7 +33,7 @@ int16_t Channels::generateHash(ChannelIndex channelNum)
|
|||||||
return -1; // invalid
|
return -1; // invalid
|
||||||
else {
|
else {
|
||||||
const char *name = getName(channelNum);
|
const char *name = getName(channelNum);
|
||||||
uint8_t h = xorHash((const uint8_t *) name, strlen(name));
|
uint8_t h = xorHash((const uint8_t *)name, strlen(name));
|
||||||
|
|
||||||
h ^= xorHash(k.bytes, k.length);
|
h ^= xorHash(k.bytes, k.length);
|
||||||
|
|
||||||
@@ -161,8 +165,8 @@ int16_t Channels::setCrypto(ChannelIndex chIndex)
|
|||||||
|
|
||||||
void Channels::initDefaults()
|
void Channels::initDefaults()
|
||||||
{
|
{
|
||||||
devicestate.channels_count = MAX_NUM_CHANNELS;
|
channelFile.channels_count = MAX_NUM_CHANNELS;
|
||||||
for (int i = 0; i < devicestate.channels_count; i++)
|
for (int i = 0; i < channelFile.channels_count; i++)
|
||||||
fixupChannel(i);
|
fixupChannel(i);
|
||||||
initDefaultChannel(0);
|
initDefaultChannel(0);
|
||||||
}
|
}
|
||||||
@@ -170,7 +174,7 @@ void Channels::initDefaults()
|
|||||||
void Channels::onConfigChanged()
|
void Channels::onConfigChanged()
|
||||||
{
|
{
|
||||||
// Make sure the phone hasn't mucked anything up
|
// Make sure the phone hasn't mucked anything up
|
||||||
for (int i = 0; i < devicestate.channels_count; i++) {
|
for (int i = 0; i < channelFile.channels_count; i++) {
|
||||||
Channel &ch = fixupChannel(i);
|
Channel &ch = fixupChannel(i);
|
||||||
|
|
||||||
if (ch.role == Channel_Role_PRIMARY)
|
if (ch.role == Channel_Role_PRIMARY)
|
||||||
@@ -180,8 +184,8 @@ void Channels::onConfigChanged()
|
|||||||
|
|
||||||
Channel &Channels::getByIndex(ChannelIndex chIndex)
|
Channel &Channels::getByIndex(ChannelIndex chIndex)
|
||||||
{
|
{
|
||||||
assert(chIndex < devicestate.channels_count);
|
assert(chIndex < channelFile.channels_count); // This should be equal to MAX_NUM_CHANNELS
|
||||||
Channel *ch = devicestate.channels + chIndex;
|
Channel *ch = channelFile.channels + chIndex;
|
||||||
return *ch;
|
return *ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,8 +196,8 @@ void Channels::setChannel(const Channel &c)
|
|||||||
// if this is the new primary, demote any existing roles
|
// if this is the new primary, demote any existing roles
|
||||||
if (c.role == Channel_Role_PRIMARY)
|
if (c.role == Channel_Role_PRIMARY)
|
||||||
for (int i = 0; i < getNumChannels(); i++)
|
for (int i = 0; i < getNumChannels(); i++)
|
||||||
if (devicestate.channels[i].role == Channel_Role_PRIMARY)
|
if (channelFile.channels[i].role == Channel_Role_PRIMARY)
|
||||||
devicestate.channels[i].role = Channel_Role_SECONDARY;
|
channelFile.channels[i].role = Channel_Role_SECONDARY;
|
||||||
|
|
||||||
old = c; // slam in the new settings/role
|
old = c; // slam in the new settings/role
|
||||||
}
|
}
|
||||||
@@ -274,11 +278,11 @@ const char *Channels::getPrimaryName()
|
|||||||
*/
|
*/
|
||||||
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
|
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
|
||||||
{
|
{
|
||||||
if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
|
if (chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
|
||||||
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex), channelHash);
|
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex),
|
||||||
|
// channelHash);
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
|
DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
|
||||||
setCrypto(chIndex);
|
setCrypto(chIndex);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ class Channels
|
|||||||
int16_t hashes[MAX_NUM_CHANNELS];
|
int16_t hashes[MAX_NUM_CHANNELS];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// Well known channel names
|
||||||
|
static const char *adminChannel, *gpioChannel, *serialChannel;
|
||||||
|
|
||||||
const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
|
const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
|
||||||
|
|
||||||
/** Return the Channel for a specified index */
|
/** Return the Channel for a specified index */
|
||||||
@@ -44,7 +48,7 @@ class Channels
|
|||||||
/** The index of the primary channel */
|
/** The index of the primary channel */
|
||||||
ChannelIndex getPrimaryIndex() const { return primaryIndex; }
|
ChannelIndex getPrimaryIndex() const { return primaryIndex; }
|
||||||
|
|
||||||
ChannelIndex getNumChannels() { return devicestate.channels_count; }
|
ChannelIndex getNumChannels() { return channelFile.channels_count; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different
|
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different
|
||||||
|
|||||||
@@ -101,25 +101,30 @@ template <class T> class MemoryPool : public Allocator<T>
|
|||||||
/// Return a buffer for use by others
|
/// Return a buffer for use by others
|
||||||
virtual void release(T *p)
|
virtual void release(T *p)
|
||||||
{
|
{
|
||||||
assert(dead.enqueue(p, 0));
|
|
||||||
assert(p >= buf &&
|
assert(p >= buf &&
|
||||||
(size_t)(p - buf) <
|
(size_t)(p - buf) <
|
||||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||||
|
assert(dead.enqueue(p, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_FREE_RTOS
|
#ifdef HAS_FREE_RTOS
|
||||||
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
|
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
|
||||||
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
|
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
|
||||||
{
|
{
|
||||||
assert(dead.enqueueFromISR(p, higherPriWoken));
|
|
||||||
assert(p >= buf &&
|
assert(p >= buf &&
|
||||||
(size_t)(p - buf) <
|
(size_t)(p - buf) <
|
||||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||||
|
assert(dead.enqueueFromISR(p, higherPriWoken));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you
|
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you
|
||||||
/// probably don't want this version).
|
/// probably don't want this version).
|
||||||
virtual T *alloc(TickType_t maxWait) { return dead.dequeuePtr(maxWait); }
|
virtual T *alloc(TickType_t maxWait)
|
||||||
|
{
|
||||||
|
T *p = dead.dequeuePtr(maxWait);
|
||||||
|
assert(p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "MeshPlugin.h"
|
#include "MeshPlugin.h"
|
||||||
|
#include "Channels.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "plugins/RoutingPlugin.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
std::vector<MeshPlugin *> *MeshPlugin::plugins;
|
std::vector<MeshPlugin *> *MeshPlugin::plugins;
|
||||||
@@ -11,7 +13,7 @@ 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 plugins has already sent a reply, it will be here. This is useful to allow
|
||||||
* the RoutingPlugin to avoid sending redundant acks
|
* the RoutingPlugin to avoid sending redundant acks
|
||||||
*/
|
*/
|
||||||
MeshPacket *MeshPlugin::currentReply;
|
MeshPacket *MeshPlugin::currentReply;
|
||||||
|
|
||||||
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
|
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
|
||||||
{
|
{
|
||||||
@@ -29,6 +31,40 @@ MeshPlugin::~MeshPlugin()
|
|||||||
assert(0); // FIXME - remove from list of plugins once someone needs this feature
|
assert(0); // FIXME - remove from list of plugins once someone needs this feature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MeshPacket *MeshPlugin::allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||||
|
{
|
||||||
|
Routing c = Routing_init_default;
|
||||||
|
|
||||||
|
c.error_reason = err;
|
||||||
|
c.which_variant = Routing_error_reason_tag;
|
||||||
|
|
||||||
|
// Now that we have moded sendAckNak up one level into the class heirarchy we can no longer assume we are a RoutingPlugin
|
||||||
|
// So we manually call pb_encode_to_bytes and specify routing port number
|
||||||
|
// auto p = allocDataProtobuf(c);
|
||||||
|
MeshPacket *p = router->allocForSending();
|
||||||
|
p->decoded.portnum = PortNum_ROUTING_APP;
|
||||||
|
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Routing_fields, &c);
|
||||||
|
|
||||||
|
p->priority = MeshPacket_Priority_ACK;
|
||||||
|
|
||||||
|
p->hop_limit = 0; // Assume just immediate neighbors for now
|
||||||
|
p->to = to;
|
||||||
|
p->decoded.request_id = idFrom;
|
||||||
|
p->channel = chIndex;
|
||||||
|
DEBUG_MSG("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshPacket *MeshPlugin::allocErrorResponse(Routing_Error err, const MeshPacket *p)
|
||||||
|
{
|
||||||
|
auto r = allocAckNak(err, getFrom(p), p->id, p->channel);
|
||||||
|
|
||||||
|
setReplyTo(r, *p);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void MeshPlugin::callPlugins(const MeshPacket &mp)
|
void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||||
{
|
{
|
||||||
// DEBUG_MSG("In call plugins\n");
|
// DEBUG_MSG("In call plugins\n");
|
||||||
@@ -46,40 +82,67 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||||||
|
|
||||||
pi.currentRequest = ∓
|
pi.currentRequest = ∓
|
||||||
|
|
||||||
// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
/// received channel
|
||||||
|
auto ch = channels.getByIndex(mp.channel);
|
||||||
|
assert(ch.has_settings);
|
||||||
|
|
||||||
|
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||||
bool wantsPacket = (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
bool wantsPacket = (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||||
// DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
|
||||||
if (wantsPacket) {
|
if (wantsPacket) {
|
||||||
|
// DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||||
pluginFound = true;
|
pluginFound = true;
|
||||||
|
|
||||||
bool handled = pi.handleReceived(mp);
|
/// Is the channel this packet arrived on acceptable? (security check)
|
||||||
|
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0);
|
||||||
|
|
||||||
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing)
|
if (!rxChannelOk) {
|
||||||
// also: we only let the one plugin send a reply, once that happens, remaining plugins are not considered
|
// no one should have already replied!
|
||||||
|
assert(!currentReply);
|
||||||
|
|
||||||
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because
|
if (mp.decoded.want_response) {
|
||||||
// currently when the phone sends things, it sends things using the local node ID as the from address. A better
|
DEBUG_MSG("packet on wrong channel, returning error\n");
|
||||||
// solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like any other
|
currentReply = pi.allocErrorResponse(Routing_Error_NOT_AUTHORIZED, &mp);
|
||||||
// node.
|
} else
|
||||||
if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
|
DEBUG_MSG("packet on wrong channel, but client didn't want response\n");
|
||||||
pi.sendResponse(mp);
|
|
||||||
DEBUG_MSG("Plugin %s sent a response\n", pi.name);
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("Plugin %s considered\n", pi.name);
|
|
||||||
}
|
bool handled = pi.handleReceived(mp);
|
||||||
if (handled) {
|
|
||||||
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
|
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious
|
||||||
break;
|
// sniffing) also: we only let the one plugin send a reply, once that happens, remaining plugins are not
|
||||||
|
// considered
|
||||||
|
|
||||||
|
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary
|
||||||
|
// because currently when the phone sends things, it sends things using the local node ID as the from address. A
|
||||||
|
// better solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like
|
||||||
|
// 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);
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Plugin %s considered\n", pi.name);
|
||||||
|
}
|
||||||
|
if (handled) {
|
||||||
|
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pi.currentRequest = NULL;
|
pi.currentRequest = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(currentReply) {
|
if (mp.decoded.want_response && toUs) {
|
||||||
DEBUG_MSG("Sending response\n");
|
if (currentReply) {
|
||||||
service.sendToMesh(currentReply);
|
DEBUG_MSG("Sending response\n");
|
||||||
currentReply = NULL;
|
service.sendToMesh(currentReply);
|
||||||
|
currentReply = NULL;
|
||||||
|
} else {
|
||||||
|
// No one wanted to reply to this requst, tell the requster that happened
|
||||||
|
DEBUG_MSG("No one responded, send a nak\n");
|
||||||
|
routingPlugin->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pluginFound)
|
if (!pluginFound)
|
||||||
@@ -95,7 +158,7 @@ void MeshPlugin::sendResponse(const MeshPacket &req)
|
|||||||
auto r = allocReply();
|
auto r = allocReply();
|
||||||
if (r) {
|
if (r) {
|
||||||
setReplyTo(r, req);
|
setReplyTo(r, req);
|
||||||
currentReply = r;
|
currentReply = r;
|
||||||
} else {
|
} else {
|
||||||
// Ignore - this is now expected behavior for routing plugin (because it ignores some replies)
|
// 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");
|
// DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
|
||||||
@@ -109,10 +172,11 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to)
|
|||||||
{
|
{
|
||||||
assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now
|
assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now
|
||||||
p->to = getFrom(&to);
|
p->to = getFrom(&to);
|
||||||
|
p->channel = to.channel; // Use the same channel that the request came in on
|
||||||
|
|
||||||
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
||||||
p->want_ack = (to.from != 0) ? to.want_ack : false;
|
p->want_ack = (to.from != 0) ? to.want_ack : false;
|
||||||
if(p->priority == MeshPacket_Priority_UNSET)
|
if (p->priority == MeshPacket_Priority_UNSET)
|
||||||
p->priority = MeshPacket_Priority_RELIABLE;
|
p->priority = MeshPacket_Priority_RELIABLE;
|
||||||
p->decoded.request_id = to.id;
|
p->decoded.request_id = to.id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "mesh/Channels.h"
|
||||||
#include "mesh/MeshTypes.h"
|
#include "mesh/MeshTypes.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifndef NO_SCREEN
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
#include <OLEDDisplayUi.h>
|
#include <OLEDDisplayUi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/** A baseclass for any mesh "plugin".
|
/** A baseclass for any mesh "plugin".
|
||||||
*
|
*
|
||||||
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||||
@@ -16,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
class MeshPlugin
|
class MeshPlugin
|
||||||
{
|
{
|
||||||
static std::vector<MeshPlugin *> *plugins;
|
static std::vector<MeshPlugin *> *plugins;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor
|
/** Constructor
|
||||||
@@ -31,22 +36,30 @@ class MeshPlugin
|
|||||||
static void callPlugins(const MeshPacket &mp);
|
static void callPlugins(const MeshPacket &mp);
|
||||||
|
|
||||||
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
|
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
|
||||||
|
#ifndef NO_SCREEN
|
||||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
|
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
|
||||||
|
#endif
|
||||||
protected:
|
protected:
|
||||||
const char *name;
|
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 recipient)
|
/* Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
|
||||||
But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those plugins can set this to
|
recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those
|
||||||
true and their handleReceived() will be called for every packet.
|
plugins can set this to true and their handleReceived() will be called for every packet.
|
||||||
*/
|
*/
|
||||||
bool isPromiscuous = false;
|
bool isPromiscuous = false;
|
||||||
|
|
||||||
|
/** If a bound channel name is set, we will only accept received packets that come in on that channel.
|
||||||
|
* A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface
|
||||||
|
* are allowed on any channel (this lets the local user do anything).
|
||||||
|
*
|
||||||
|
* We will send responses on the same channel that the request arrived on.
|
||||||
|
*/
|
||||||
|
const char *boundChannel = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this plugin is currently handling a request currentRequest will be preset
|
* If this plugin is currently handling a request currentRequest will be preset
|
||||||
* to the packet with the request. This is mostly useful for reply handlers.
|
* 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
|
* Note: this can be static because we are guaranteed to be processing only one
|
||||||
* plugin at a time.
|
* plugin at a time.
|
||||||
*/
|
*/
|
||||||
@@ -78,16 +91,18 @@ class MeshPlugin
|
|||||||
*/
|
*/
|
||||||
virtual bool wantUIFrame() { return false; }
|
virtual bool wantUIFrame() { return false; }
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 plugins has already sent a reply, it will be here. This is useful to allow
|
||||||
* the RoutingPlugin to avoid sending redundant acks
|
* the RoutingPlugin to avoid sending redundant acks
|
||||||
*/
|
*/
|
||||||
static MeshPacket *currentReply;
|
static MeshPacket *currentReply;
|
||||||
friend class ReliableRouter;
|
friend class ReliableRouter;
|
||||||
|
|
||||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
* so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply()
|
* so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply()
|
||||||
@@ -96,7 +111,7 @@ class MeshPlugin
|
|||||||
void sendResponse(const MeshPacket &req);
|
void sendResponse(const MeshPacket &req);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
/** 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.
|
* 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);
|
||||||
@@ -104,7 +104,7 @@ bool MeshService::reloadConfig()
|
|||||||
// This will also update the region as needed
|
// This will also update the region as needed
|
||||||
bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
|
bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
|
||||||
|
|
||||||
configChanged.notifyObservers(NULL);
|
configChanged.notifyObservers(NULL); // This will cause radio hardware to change freqs etc
|
||||||
nodeDB.saveToDisk();
|
nodeDB.saveToDisk();
|
||||||
|
|
||||||
return didReset;
|
return didReset;
|
||||||
@@ -114,7 +114,7 @@ bool MeshService::reloadConfig()
|
|||||||
void MeshService::reloadOwner()
|
void MeshService::reloadOwner()
|
||||||
{
|
{
|
||||||
assert(nodeInfoPlugin);
|
assert(nodeInfoPlugin);
|
||||||
if(nodeInfoPlugin)
|
if (nodeInfoPlugin)
|
||||||
nodeInfoPlugin->sendOurNodeInfo();
|
nodeInfoPlugin->sendOurNodeInfo();
|
||||||
nodeDB.saveToDisk();
|
nodeDB.saveToDisk();
|
||||||
}
|
}
|
||||||
@@ -172,13 +172,12 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
|||||||
assert(node);
|
assert(node);
|
||||||
|
|
||||||
if (node->has_position) {
|
if (node->has_position) {
|
||||||
if(positionPlugin) {
|
if (positionPlugin) {
|
||||||
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||||
positionPlugin->sendOurPosition(dest, wantReplies);
|
positionPlugin->sendOurPosition(dest, wantReplies);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (nodeInfoPlugin) {
|
||||||
if(nodeInfoPlugin) {
|
|
||||||
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||||
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
||||||
}
|
}
|
||||||
@@ -198,10 +197,13 @@ NodeInfo *MeshService::refreshMyNodeInfo()
|
|||||||
|
|
||||||
Position &position = node->position;
|
Position &position = node->position;
|
||||||
|
|
||||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
// Update our local node info with our time (even if we don't decide to update anyone else)
|
||||||
position.time =
|
node->last_heard =
|
||||||
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
|
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
|
||||||
|
|
||||||
|
// For the time in the position field, only set that if we have a real GPS clock
|
||||||
|
position.time = getValidTime(RTCQualityGPS);
|
||||||
|
|
||||||
position.battery_level = powerStatus->getBatteryChargePercent();
|
position.battery_level = powerStatus->getBatteryChargePercent();
|
||||||
updateBatteryLevel(position.battery_level);
|
updateBatteryLevel(position.battery_level);
|
||||||
|
|
||||||
|
|||||||
@@ -84,13 +84,12 @@ class MeshService
|
|||||||
NodeInfo *refreshMyNodeInfo();
|
NodeInfo *refreshMyNodeInfo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
||||||
/// returns 0 to allow futher processing
|
/// returns 0 to allow futher processing
|
||||||
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
||||||
|
|
||||||
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it needs
|
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
|
||||||
/// to keep the packet around it makes a copy
|
/// needs to keep the packet around it makes a copy
|
||||||
int handleFromRadio(const MeshPacket *p);
|
int handleFromRadio(const MeshPacket *p);
|
||||||
friend class RoutingPlugin;
|
friend class RoutingPlugin;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
#include "mesh/http/WiFiAPClient.h"
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
|
#include "plugins/esp32/StoreForwardPlugin.h"
|
||||||
|
#include <Preferences.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NodeDB nodeDB;
|
NodeDB nodeDB;
|
||||||
@@ -30,7 +32,8 @@ NodeDB nodeDB;
|
|||||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||||
EXT_RAM_ATTR DeviceState devicestate;
|
EXT_RAM_ATTR DeviceState devicestate;
|
||||||
MyNodeInfo &myNodeInfo = devicestate.my_node;
|
MyNodeInfo &myNodeInfo = devicestate.my_node;
|
||||||
RadioConfig &radioConfig = devicestate.radio;
|
RadioConfig radioConfig;
|
||||||
|
ChannelFile channelFile;
|
||||||
|
|
||||||
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
|
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
|
||||||
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
||||||
@@ -67,10 +70,11 @@ NodeNum displayedNodeNum;
|
|||||||
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
|
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node.
|
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
|
||||||
* If from is zero this function returns our node number instead
|
* the local node. If from is zero this function returns our node number instead
|
||||||
*/
|
*/
|
||||||
NodeNum getFrom(const MeshPacket *p) {
|
NodeNum getFrom(const MeshPacket *p)
|
||||||
|
{
|
||||||
return (p->from == 0) ? nodeDB.getNodeNum() : p->from;
|
return (p->from == 0) ? nodeDB.getNodeNum() : p->from;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,16 +84,17 @@ bool NodeDB::resetRadioConfig()
|
|||||||
|
|
||||||
radioGeneration++;
|
radioGeneration++;
|
||||||
|
|
||||||
|
radioConfig.has_preferences = true;
|
||||||
if (radioConfig.preferences.factory_reset) {
|
if (radioConfig.preferences.factory_reset) {
|
||||||
DEBUG_MSG("Performing factory reset!\n");
|
DEBUG_MSG("Performing factory reset!\n");
|
||||||
installDefaultDeviceState();
|
installDefaultDeviceState();
|
||||||
didFactoryReset = true;
|
didFactoryReset = true;
|
||||||
} else if (devicestate.channels_count == 0) {
|
}
|
||||||
|
|
||||||
|
if (channelFile.channels_count != MAX_NUM_CHANNELS) {
|
||||||
DEBUG_MSG("Setting default channel and radio preferences!\n");
|
DEBUG_MSG("Setting default channel and radio preferences!\n");
|
||||||
|
|
||||||
channels.initDefaults();
|
channels.initDefaults();
|
||||||
|
|
||||||
radioConfig.has_preferences = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channels.onConfigChanged();
|
channels.onConfigChanged();
|
||||||
@@ -117,6 +122,18 @@ bool NodeDB::resetRadioConfig()
|
|||||||
return didFactoryReset;
|
return didFactoryReset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeDB::installDefaultRadioConfig()
|
||||||
|
{
|
||||||
|
memset(&radioConfig, 0, sizeof(radioConfig));
|
||||||
|
radioConfig.has_preferences = true;
|
||||||
|
resetRadioConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeDB::installDefaultChannels()
|
||||||
|
{
|
||||||
|
memset(&channelFile, 0, sizeof(channelFile));
|
||||||
|
}
|
||||||
|
|
||||||
void NodeDB::installDefaultDeviceState()
|
void NodeDB::installDefaultDeviceState()
|
||||||
{
|
{
|
||||||
// We try to preserve the region setting because it will really bum users out if we discard it
|
// We try to preserve the region setting because it will really bum users out if we discard it
|
||||||
@@ -129,14 +146,11 @@ void NodeDB::installDefaultDeviceState()
|
|||||||
|
|
||||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||||
devicestate.has_my_node = true;
|
devicestate.has_my_node = true;
|
||||||
devicestate.has_radio = true;
|
|
||||||
devicestate.has_owner = true;
|
devicestate.has_owner = true;
|
||||||
devicestate.radio.has_preferences = true;
|
|
||||||
devicestate.node_db_count = 0;
|
devicestate.node_db_count = 0;
|
||||||
|
devicestate.version = DEVICESTATE_CUR_VER;
|
||||||
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
||||||
|
|
||||||
resetRadioConfig();
|
|
||||||
|
|
||||||
// default to no GPS, until one has been found by probing
|
// default to no GPS, until one has been found by probing
|
||||||
myNodeInfo.has_gps = false;
|
myNodeInfo.has_gps = false;
|
||||||
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
|
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
|
||||||
@@ -158,6 +172,9 @@ void NodeDB::installDefaultDeviceState()
|
|||||||
radioConfig.preferences.region = oldRegionCode;
|
radioConfig.preferences.region = oldRegionCode;
|
||||||
if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date
|
if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date
|
||||||
strcpy(myNodeInfo.region, oldRegion.c_str());
|
strcpy(myNodeInfo.region, oldRegion.c_str());
|
||||||
|
|
||||||
|
installDefaultChannels();
|
||||||
|
installDefaultRadioConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeDB::init()
|
void NodeDB::init()
|
||||||
@@ -181,17 +198,25 @@ void NodeDB::init()
|
|||||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||||
pickNewNodeNum();
|
pickNewNodeNum();
|
||||||
|
|
||||||
|
// Set our board type so we can share it with others
|
||||||
|
owner.hw_model = HW_VENDOR;
|
||||||
|
|
||||||
// Include our owner in the node db under our nodenum
|
// Include our owner in the node db under our nodenum
|
||||||
NodeInfo *info = getOrCreateNode(getNodeNum());
|
NodeInfo *info = getOrCreateNode(getNodeNum());
|
||||||
info->user = owner;
|
info->user = owner;
|
||||||
info->has_user = true;
|
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
|
// We set these _after_ loading from disk - because they come from the build and are more trusted than
|
||||||
// what is stored in flash
|
// what is stored in flash
|
||||||
if (xstr(HW_VERSION)[0])
|
// if (xstr(HW_VERSION)[0])
|
||||||
strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
|
// strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
|
||||||
else
|
// else DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build
|
||||||
DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build flag
|
// 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.
|
// Check for the old style of region code strings, if found, convert to the new enum.
|
||||||
// Those strings will look like "1.0-EU433"
|
// Those strings will look like "1.0-EU433"
|
||||||
@@ -205,12 +230,23 @@ void NodeDB::init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
|
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
|
||||||
strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model));
|
|
||||||
|
// 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);
|
||||||
|
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
|
||||||
|
preferences.end();
|
||||||
|
DEBUG_MSG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||||
|
|
||||||
DEBUG_MSG("legacy_region=%s, region=%d, NODENUM=0x%x, dbsize=%d\n", myNodeInfo.region, radioConfig.preferences.region,
|
DEBUG_MSG("region=%d, NODENUM=0x%x, dbsize=%d\n", radioConfig.preferences.region, myNodeInfo.my_node_num, *numNodes);
|
||||||
myNodeInfo.my_node_num, *numNodes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We reserve a few nodenums for future use
|
// We reserve a few nodenums for future use
|
||||||
@@ -240,84 +276,134 @@ void NodeDB::pickNewNodeNum()
|
|||||||
myNodeInfo.my_node_num = r;
|
myNodeInfo.my_node_num = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *preffile = "/db.proto";
|
static const char *preffileOld = "/db.proto";
|
||||||
const char *preftmp = "/db.proto.tmp";
|
static const char *preffile = "/prefs/db.proto";
|
||||||
|
static const char *radiofile = "/prefs/radio.proto";
|
||||||
|
static const char *channelfile = "/prefs/channels.proto";
|
||||||
|
// const char *preftmp = "/db.proto.tmp";
|
||||||
|
|
||||||
void NodeDB::loadFromDisk()
|
/** 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 FS
|
||||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||||
|
|
||||||
auto f = FS.open(preffile);
|
auto f = FS.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool okay = false;
|
||||||
if (f) {
|
if (f) {
|
||||||
DEBUG_MSG("Loading saved preferences\n");
|
DEBUG_MSG("Loading %s\n", filename);
|
||||||
pb_istream_t stream = {&readcb, &f, DeviceState_size};
|
pb_istream_t stream = {&readcb, &f, protoSize};
|
||||||
|
|
||||||
// DEBUG_MSG("Preload channel name=%s\n", channelSettings.name);
|
// DEBUG_MSG("Preload channel name=%s\n", channelSettings.name);
|
||||||
|
|
||||||
memset(&devicestate, 0, sizeof(devicestate));
|
memset(dest_struct, 0, objSize);
|
||||||
if (!pb_decode(&stream, DeviceState_fields, &devicestate)) {
|
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||||
DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||||
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
|
|
||||||
// FIXME - report failure to phone
|
|
||||||
} else {
|
} else {
|
||||||
if (devicestate.version < DEVICESTATE_MIN_VER) {
|
okay = true;
|
||||||
DEBUG_MSG("Warn: devicestate is old, discarding\n");
|
|
||||||
installDefaultDeviceState();
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version);
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEBUG_MSG("Postload channel name=%s\n", channelSettings.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("No saved preferences found\n");
|
DEBUG_MSG("No %s preferences found\n", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
DEBUG_MSG("ERROR: Filesystem not implemented\n");
|
DEBUG_MSG("ERROR: Filesystem not implemented\n");
|
||||||
#endif
|
#endif
|
||||||
|
return okay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeDB::loadFromDisk()
|
||||||
|
{
|
||||||
|
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||||
|
if (!loadProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate)) {
|
||||||
|
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
|
||||||
|
} else {
|
||||||
|
if (devicestate.version < DEVICESTATE_MIN_VER) {
|
||||||
|
DEBUG_MSG("Warn: devicestate %d is old, discarding\n", devicestate.version);
|
||||||
|
installDefaultDeviceState();
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loadProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig)) {
|
||||||
|
installDefaultRadioConfig(); // Our in RAM copy might now be corrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loadProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) {
|
||||||
|
installDefaultChannels(); // Our in RAM copy might now be corrupt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
// 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);
|
||||||
|
bool okay = false;
|
||||||
|
if (f) {
|
||||||
|
DEBUG_MSG("Saving %s\n", filename);
|
||||||
|
pb_ostream_t stream = {&writecb, &f, protoSize};
|
||||||
|
|
||||||
|
if (!pb_encode(&stream, fields, dest_struct)) {
|
||||||
|
DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||||
|
} else {
|
||||||
|
okay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
// brief window of risk here ;-)
|
||||||
|
if (!FS.remove(filename))
|
||||||
|
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
||||||
|
if (!FS.rename(filenameTmp.c_str(), filename))
|
||||||
|
DEBUG_MSG("Error: can't rename new pref file\n");
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Can't write prefs\n");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
DEBUG_MSG("ERROR: Filesystem not implemented\n");
|
||||||
|
#endif
|
||||||
|
return okay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeDB::saveChannelsToDisk()
|
||||||
|
{
|
||||||
|
if (!devicestate.no_save) {
|
||||||
|
#ifdef FS
|
||||||
|
FS.mkdir("/prefs");
|
||||||
|
#endif
|
||||||
|
saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeDB::saveToDisk()
|
void NodeDB::saveToDisk()
|
||||||
{
|
{
|
||||||
#ifdef FS
|
|
||||||
if (!devicestate.no_save) {
|
if (!devicestate.no_save) {
|
||||||
auto f = FS.open(preftmp, FILE_O_WRITE);
|
#ifdef FS
|
||||||
if (f) {
|
FS.mkdir("/prefs");
|
||||||
DEBUG_MSG("Writing preferences\n");
|
#endif
|
||||||
|
bool okay = saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
|
||||||
|
okay &= saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
|
||||||
|
saveChannelsToDisk();
|
||||||
|
|
||||||
pb_ostream_t stream = {&writecb, &f, SIZE_MAX, 0};
|
// remove any pre 1.2 pref files, turn on after 1.2 is in beta
|
||||||
|
// if(okay) FS.remove(preffileOld);
|
||||||
// DEBUG_MSG("Presave channel name=%s\n", channelSettings.name);
|
|
||||||
|
|
||||||
devicestate.version = DEVICESTATE_CUR_VER;
|
|
||||||
if (!pb_encode(&stream, DeviceState_fields, &devicestate)) {
|
|
||||||
DEBUG_MSG("Error: can't write protobuf %s\n", PB_GET_ERROR(&stream));
|
|
||||||
// FIXME - report failure to phone
|
|
||||||
|
|
||||||
f.close();
|
|
||||||
} else {
|
|
||||||
// Success - replace the old file
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
// brief window of risk here ;-)
|
|
||||||
if (!FS.remove(preffile))
|
|
||||||
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
|
||||||
if (!FS.rename(preftmp, preffile))
|
|
||||||
DEBUG_MSG("Error: can't rename new pref file\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG("ERROR: can't write prefs\n"); // FIXME report to app
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
DEBUG_MSG("ERROR filesystem not implemented\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeInfo *NodeDB::readNextInfo()
|
const NodeInfo *NodeDB::readNextInfo()
|
||||||
@@ -333,8 +419,7 @@ uint32_t sinceLastSeen(const NodeInfo *n)
|
|||||||
{
|
{
|
||||||
uint32_t now = getTime();
|
uint32_t now = getTime();
|
||||||
|
|
||||||
uint32_t last_seen = n->position.time;
|
int delta = (int)(now - n->last_heard);
|
||||||
int delta = (int)(now - last_seen);
|
|
||||||
if (delta < 0) // our clock must be slightly off still - not set from GPS yet
|
if (delta < 0) // our clock must be slightly off still - not set from GPS yet
|
||||||
delta = 0;
|
delta = 0;
|
||||||
|
|
||||||
@@ -368,14 +453,16 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
|
|||||||
// Be careful to only update fields that have been set by the sender
|
// Be careful to only update fields that have been set by the sender
|
||||||
// A lot of position reports don't have time populated. In that case, be careful to not blow away the time we
|
// A lot of position reports don't have time populated. In that case, be careful to not blow away the time we
|
||||||
// recorded based on the packet rxTime
|
// recorded based on the packet rxTime
|
||||||
if (!info->position.time && p.time)
|
if (p.time)
|
||||||
info->position.time = p.time;
|
info->position.time = p.time;
|
||||||
if(p.battery_level)
|
if (p.battery_level)
|
||||||
info->position.battery_level = p.battery_level;
|
info->position.battery_level = p.battery_level;
|
||||||
if (p.latitude_i || p.longitude_i) {
|
if (p.latitude_i || p.longitude_i) {
|
||||||
info->position.latitude_i = p.latitude_i;
|
info->position.latitude_i = p.latitude_i;
|
||||||
info->position.longitude_i = p.longitude_i;
|
info->position.longitude_i = p.longitude_i;
|
||||||
}
|
}
|
||||||
|
if (p.altitude)
|
||||||
|
info->position.altitude = p.altitude;
|
||||||
info->has_position = true;
|
info->has_position = true;
|
||||||
updateGUIforNode = info;
|
updateGUIforNode = info;
|
||||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||||
@@ -411,17 +498,16 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p)
|
|||||||
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
||||||
void NodeDB::updateFrom(const MeshPacket &mp)
|
void NodeDB::updateFrom(const MeshPacket &mp)
|
||||||
{
|
{
|
||||||
if (mp.which_payloadVariant == MeshPacket_decoded_tag) {
|
if (mp.which_payloadVariant == MeshPacket_decoded_tag && mp.from) {
|
||||||
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||||
|
|
||||||
NodeInfo *info = getOrCreateNode(getFrom(&mp));
|
NodeInfo *info = getOrCreateNode(getFrom(&mp));
|
||||||
|
|
||||||
if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
|
if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard
|
||||||
info->has_position = true; // at least the time is valid
|
info->last_heard = mp.rx_time;
|
||||||
info->position.time = mp.rx_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
|
if (mp.rx_snr)
|
||||||
|
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
|
|
||||||
extern DeviceState devicestate;
|
extern DeviceState devicestate;
|
||||||
|
extern ChannelFile channelFile;
|
||||||
extern MyNodeInfo &myNodeInfo;
|
extern MyNodeInfo &myNodeInfo;
|
||||||
extern RadioConfig &radioConfig;
|
extern RadioConfig radioConfig;
|
||||||
extern User &owner;
|
extern User &owner;
|
||||||
|
|
||||||
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
|
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
|
||||||
@@ -42,7 +43,7 @@ class NodeDB
|
|||||||
void init();
|
void init();
|
||||||
|
|
||||||
/// write to flash
|
/// write to flash
|
||||||
void saveToDisk();
|
void saveToDisk(), saveChannelsToDisk();
|
||||||
|
|
||||||
/** Reinit radio config if needed, because either:
|
/** Reinit radio config if needed, because either:
|
||||||
* a) sometimes a buggy android app might send us bogus settings or
|
* a) sometimes a buggy android app might send us bogus settings or
|
||||||
@@ -117,7 +118,7 @@ class NodeDB
|
|||||||
void loadFromDisk();
|
void loadFromDisk();
|
||||||
|
|
||||||
/// Reinit device state from scratch (not loading from disk)
|
/// Reinit device state from scratch (not loading from disk)
|
||||||
void installDefaultDeviceState();
|
void installDefaultDeviceState(), installDefaultRadioConfig(), installDefaultChannels();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "PhoneAPI.h"
|
#include "PhoneAPI.h"
|
||||||
|
#include "Channels.h"
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RadioInterface.h"
|
#include "RadioInterface.h"
|
||||||
#include "Channels.h"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
|
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
|
||||||
@@ -15,33 +15,52 @@
|
|||||||
#error ToRadio is too big
|
#error ToRadio is too big
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PhoneAPI::PhoneAPI() {}
|
PhoneAPI::PhoneAPI()
|
||||||
|
|
||||||
void PhoneAPI::init()
|
|
||||||
{
|
{
|
||||||
observe(&service.fromNumChanged);
|
lastContactMsec = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
PhoneAPI::~PhoneAPI() {
|
PhoneAPI::~PhoneAPI()
|
||||||
|
{
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhoneAPI::close() {
|
void PhoneAPI::handleStartConfig()
|
||||||
unobserve();
|
{
|
||||||
state = STATE_SEND_NOTHING;
|
if (!isConnected()) {
|
||||||
bool oldConnected = isConnected;
|
onConnectionChanged(true);
|
||||||
isConnected = false;
|
observe(&service.fromNumChanged);
|
||||||
if(oldConnected != isConnected)
|
}
|
||||||
onConnectionChanged(isConnected);
|
|
||||||
|
// even if we were already connected - restart our state machine
|
||||||
|
state = STATE_SEND_MY_INFO;
|
||||||
|
|
||||||
|
DEBUG_MSG("Reset nodeinfo read pointer\n");
|
||||||
|
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
|
||||||
|
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
|
||||||
|
// this will break once we have multiple instances of PhoneAPI running independently
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneAPI::close()
|
||||||
|
{
|
||||||
|
if (state != STATE_SEND_NOTHING) {
|
||||||
|
state = STATE_SEND_NOTHING;
|
||||||
|
|
||||||
|
unobserve();
|
||||||
|
releasePhonePacket(); // Don't leak phone packets on shutdown
|
||||||
|
|
||||||
|
onConnectionChanged(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhoneAPI::checkConnectionTimeout()
|
void PhoneAPI::checkConnectionTimeout()
|
||||||
{
|
{
|
||||||
if (isConnected) {
|
if (isConnected()) {
|
||||||
bool newConnected = (millis() - lastContactMsec < getPref_phone_timeout_secs() * 1000L);
|
uint32_t now = millis();
|
||||||
if (!newConnected) {
|
bool newContact = (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL;
|
||||||
isConnected = false;
|
if (!newContact) {
|
||||||
onConnectionChanged(isConnected);
|
DEBUG_MSG("Timed out on phone contact, dropping phone connection\n");
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,34 +68,28 @@ void PhoneAPI::checkConnectionTimeout()
|
|||||||
/**
|
/**
|
||||||
* Handle a ToRadio protobuf
|
* Handle a ToRadio protobuf
|
||||||
*/
|
*/
|
||||||
void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||||
{
|
{
|
||||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
|
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
|
||||||
lastContactMsec = millis();
|
lastContactMsec = millis();
|
||||||
if (!isConnected) {
|
|
||||||
isConnected = true;
|
|
||||||
onConnectionChanged(isConnected);
|
|
||||||
}
|
|
||||||
// return (lastContactMsec != 0) &&
|
// return (lastContactMsec != 0) &&
|
||||||
|
|
||||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
||||||
switch (toRadioScratch.which_payloadVariant) {
|
switch (toRadioScratch.which_payloadVariant) {
|
||||||
case ToRadio_packet_tag: {
|
case ToRadio_packet_tag:
|
||||||
MeshPacket &p = toRadioScratch.packet;
|
return handleToRadioPacket(toRadioScratch.packet);
|
||||||
printPacket("PACKET FROM PHONE", &p);
|
|
||||||
service.handleToRadio(p);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ToRadio_want_config_id_tag:
|
case ToRadio_want_config_id_tag:
|
||||||
config_nonce = toRadioScratch.want_config_id;
|
config_nonce = toRadioScratch.want_config_id;
|
||||||
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
|
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
|
||||||
state = STATE_SEND_MY_INFO;
|
|
||||||
|
|
||||||
DEBUG_MSG("Reset nodeinfo read pointer\n");
|
handleStartConfig();
|
||||||
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
|
break;
|
||||||
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
|
|
||||||
// this will break once we have multiple instances of PhoneAPI running independently
|
case ToRadio_disconnect_tag:
|
||||||
|
close();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -86,6 +99,8 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("Error: ignoring malformed toradio\n");
|
DEBUG_MSG("Error: ignoring malformed toradio\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,14 +135,12 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
|||||||
case STATE_SEND_MY_INFO:
|
case STATE_SEND_MY_INFO:
|
||||||
// If the user has specified they don't want our node to share its location, make sure to tell the phone
|
// If the user has specified they don't want our node to share its location, make sure to tell the phone
|
||||||
// app not to send locations on our behalf.
|
// app not to send locations on our behalf.
|
||||||
myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled)
|
myNodeInfo.has_gps = gps && gps->isConnected(); // Update with latest GPS connect info
|
||||||
? true
|
|
||||||
: (gps && gps->isConnected()); // Update with latest GPS connect info
|
|
||||||
fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
|
fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
|
||||||
fromRadioScratch.my_info = myNodeInfo;
|
fromRadioScratch.my_info = myNodeInfo;
|
||||||
state = STATE_SEND_NODEINFO;
|
state = STATE_SEND_NODEINFO;
|
||||||
|
|
||||||
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
|
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_SEND_NODEINFO: {
|
case STATE_SEND_NODEINFO: {
|
||||||
@@ -135,7 +148,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
|||||||
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
|
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
|
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->last_heard, info->user.id,
|
||||||
info->user.long_name);
|
info->user.long_name);
|
||||||
fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
|
fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
|
||||||
fromRadioScratch.node_info = *info;
|
fromRadioScratch.node_info = *info;
|
||||||
@@ -156,20 +169,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
|||||||
state = STATE_SEND_PACKETS;
|
state = STATE_SEND_PACKETS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_LEGACY: // Treat as the same as send packets
|
|
||||||
case STATE_SEND_PACKETS:
|
case STATE_SEND_PACKETS:
|
||||||
// Do we have a message from the mesh?
|
// Do we have a message from the mesh?
|
||||||
if (packetForPhone) {
|
if (packetForPhone) {
|
||||||
|
|
||||||
printPacket("phone downloaded packet", packetForPhone);
|
printPacket("phone downloaded packet", packetForPhone);
|
||||||
|
|
||||||
// Encapsulate as a FromRadio packet
|
// Encapsulate as a FromRadio packet
|
||||||
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
|
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
|
||||||
fromRadioScratch.packet = *packetForPhone;
|
fromRadioScratch.packet = *packetForPhone;
|
||||||
|
|
||||||
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
|
|
||||||
packetForPhone = NULL;
|
|
||||||
}
|
}
|
||||||
|
releasePhonePacket();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -188,6 +197,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhoneAPI::handleDisconnect() {}
|
||||||
|
|
||||||
|
void PhoneAPI::releasePhonePacket()
|
||||||
|
{
|
||||||
|
if (packetForPhone) {
|
||||||
|
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
|
||||||
|
packetForPhone = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if we have data available to send to the phone
|
* Return true if we have data available to send to the phone
|
||||||
*/
|
*/
|
||||||
@@ -208,7 +227,6 @@ bool PhoneAPI::available()
|
|||||||
case STATE_SEND_COMPLETE_ID:
|
case STATE_SEND_COMPLETE_ID:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case STATE_LEGACY: // Treat as the same as send packets
|
|
||||||
case STATE_SEND_PACKETS: {
|
case STATE_SEND_PACKETS: {
|
||||||
// Try to pull a new packet from the service (if we haven't already)
|
// Try to pull a new packet from the service (if we haven't already)
|
||||||
if (!packetForPhone)
|
if (!packetForPhone)
|
||||||
@@ -228,7 +246,13 @@ bool PhoneAPI::available()
|
|||||||
/**
|
/**
|
||||||
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
|
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
|
||||||
*/
|
*/
|
||||||
void PhoneAPI::handleToRadioPacket(MeshPacket *p) {}
|
bool PhoneAPI::handleToRadioPacket(MeshPacket &p)
|
||||||
|
{
|
||||||
|
printPacket("PACKET FROM PHONE", &p);
|
||||||
|
service.handleToRadio(p);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||||
int PhoneAPI::onNotify(uint32_t newValue)
|
int PhoneAPI::onNotify(uint32_t newValue)
|
||||||
@@ -236,7 +260,7 @@ int PhoneAPI::onNotify(uint32_t newValue)
|
|||||||
checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version doesn't call this
|
checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version doesn't call this
|
||||||
// from idle)
|
// from idle)
|
||||||
|
|
||||||
if (state == STATE_SEND_PACKETS || state == STATE_LEGACY) {
|
if (state == STATE_SEND_PACKETS) {
|
||||||
DEBUG_MSG("Telling client we have new packets %u\n", newValue);
|
DEBUG_MSG("Telling client we have new packets %u\n", newValue);
|
||||||
onNowHasData(newValue);
|
onNowHasData(newValue);
|
||||||
} else
|
} else
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ class PhoneAPI
|
|||||||
: public Observer<uint32_t> // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
|
: public Observer<uint32_t> // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
|
||||||
{
|
{
|
||||||
enum State {
|
enum State {
|
||||||
STATE_LEGACY, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API
|
STATE_UNUSED, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API
|
||||||
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
|
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_MY_INFO, // send our my info record
|
||||||
// STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet
|
// 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_OWNER, no need to send Owner specially, it is just part of the nodedb
|
||||||
@@ -58,17 +59,15 @@ class PhoneAPI
|
|||||||
/// Destructor - calls close()
|
/// Destructor - calls close()
|
||||||
virtual ~PhoneAPI();
|
virtual ~PhoneAPI();
|
||||||
|
|
||||||
/// Do late init that can't happen at constructor time
|
|
||||||
virtual void init();
|
|
||||||
|
|
||||||
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
|
// 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.
|
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
|
||||||
virtual void close();
|
virtual void close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a ToRadio protobuf
|
* Handle a ToRadio protobuf
|
||||||
|
* @return true true if a packet was queued for sending (so that caller can yield)
|
||||||
*/
|
*/
|
||||||
virtual void handleToRadio(const uint8_t *buf, size_t len);
|
virtual bool handleToRadio(const uint8_t *buf, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next packet we want to send to the phone
|
* Get the next packet we want to send to the phone
|
||||||
@@ -83,17 +82,16 @@ class PhoneAPI
|
|||||||
*/
|
*/
|
||||||
bool available();
|
bool available();
|
||||||
|
|
||||||
protected:
|
bool isConnected() { return state != STATE_SEND_NOTHING; }
|
||||||
/// Are we currently connected to a client?
|
|
||||||
bool isConnected = false;
|
|
||||||
|
|
||||||
|
protected:
|
||||||
/// Our fromradio packet while it is being assembled
|
/// Our fromradio packet while it is being assembled
|
||||||
FromRadio fromRadioScratch;
|
FromRadio fromRadioScratch;
|
||||||
|
|
||||||
/// Hookable to find out when connection changes
|
/// Hookable to find out when connection changes
|
||||||
virtual void onConnectionChanged(bool connected) {}
|
virtual void onConnectionChanged(bool connected) {}
|
||||||
|
|
||||||
/// If we haven't heard from the other side in a while then say not connected
|
/// If we haven't heard from the other side in a while then say not connected
|
||||||
void checkConnectionTimeout();
|
void checkConnectionTimeout();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,11 +99,22 @@ class PhoneAPI
|
|||||||
*/
|
*/
|
||||||
virtual void onNowHasData(uint32_t fromRadioNum) {}
|
virtual void onNowHasData(uint32_t fromRadioNum) {}
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
|
* Subclasses can use this to find out when a client drops the link
|
||||||
*/
|
*/
|
||||||
void handleToRadioPacket(MeshPacket *p);
|
virtual void handleDisconnect();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void releasePhonePacket();
|
||||||
|
|
||||||
|
/// begin a new connection
|
||||||
|
void handleStartConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
|
||||||
|
* @return true true if a packet was queued for sending
|
||||||
|
*/
|
||||||
|
bool handleToRadioPacket(MeshPacket &p);
|
||||||
|
|
||||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||||
virtual int onNotify(uint32_t newValue);
|
virtual int onNotify(uint32_t newValue);
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ bool RF95Interface::init()
|
|||||||
{
|
{
|
||||||
RadioLibInterface::init();
|
RadioLibInterface::init();
|
||||||
|
|
||||||
applyModemConfig();
|
|
||||||
|
|
||||||
if (power == 0)
|
if (power == 0)
|
||||||
power = POWER_DEFAULT;
|
power = POWER_DEFAULT;
|
||||||
|
|
||||||
@@ -86,24 +84,25 @@ void INTERRUPT_ATTR RF95Interface::disableInterrupt()
|
|||||||
lora->clearDio0Action();
|
lora->clearDio0Action();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool RF95Interface::reconfigure()
|
bool RF95Interface::reconfigure()
|
||||||
{
|
{
|
||||||
applyModemConfig();
|
RadioLibInterface::reconfigure();
|
||||||
|
|
||||||
// set mode to standby
|
// set mode to standby
|
||||||
setStandby();
|
setStandby();
|
||||||
|
|
||||||
// configure publicly accessible settings
|
// configure publicly accessible settings
|
||||||
int err = lora->setSpreadingFactor(sf);
|
int err = lora->setSpreadingFactor(sf);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
err = lora->setBandwidth(bw);
|
err = lora->setBandwidth(bw);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
err = lora->setCodingRate(cr);
|
err = lora->setCodingRate(cr);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
err = lora->setSyncWord(syncWord);
|
err = lora->setSyncWord(syncWord);
|
||||||
assert(err == ERR_NONE);
|
assert(err == ERR_NONE);
|
||||||
@@ -115,12 +114,14 @@ bool RF95Interface::reconfigure()
|
|||||||
assert(err == ERR_NONE);
|
assert(err == ERR_NONE);
|
||||||
|
|
||||||
err = lora->setFrequency(freq);
|
err = lora->setFrequency(freq);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
if (power > MAX_POWER) // This chip has lower power limits than some
|
if (power > MAX_POWER) // This chip has lower power limits than some
|
||||||
power = MAX_POWER;
|
power = MAX_POWER;
|
||||||
err = lora->setOutputPower(power);
|
err = lora->setOutputPower(power);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
startReceive(); // restart receiving
|
startReceive(); // restart receiving
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "RadioInterface.h"
|
#include "RadioInterface.h"
|
||||||
#include "Channels.h"
|
#include "Channels.h"
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "assert.h"
|
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
|
#include "assert.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
@@ -31,8 +31,8 @@ const RegionInfo regions[] = {
|
|||||||
|
|
||||||
/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2):
|
/* 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
|
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018)
|
||||||
We have 3 options for 868 MHz:
|
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.
|
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
|
866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports
|
||||||
@@ -112,6 +112,8 @@ uint32_t RadioInterface::getPacketTime(MeshPacket *p)
|
|||||||
/** The delay to use for retransmitting dropped packets */
|
/** The delay to use for retransmitting dropped packets */
|
||||||
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||||
{
|
{
|
||||||
|
assert(shortPacketMsec); // Better be non zero
|
||||||
|
|
||||||
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range
|
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range
|
||||||
return random(9 * shortPacketMsec, 10 * shortPacketMsec);
|
return random(9 * shortPacketMsec, 10 * shortPacketMsec);
|
||||||
}
|
}
|
||||||
@@ -153,6 +155,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
|||||||
if (s.dest != 0)
|
if (s.dest != 0)
|
||||||
DEBUG_MSG(" dest=%08x", s.dest);
|
DEBUG_MSG(" dest=%08x", s.dest);
|
||||||
|
|
||||||
|
if (s.request_id)
|
||||||
|
DEBUG_MSG(" requestId=%0x", s.request_id);
|
||||||
|
|
||||||
/* now inside Data and therefore kinda opaque
|
/* now inside Data and therefore kinda opaque
|
||||||
if (s.which_ackVariant == SubPacket_success_id_tag)
|
if (s.which_ackVariant == SubPacket_success_id_tag)
|
||||||
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
|
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
|
||||||
@@ -182,6 +187,12 @@ RadioInterface::RadioInterface()
|
|||||||
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
|
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RadioInterface::reconfigure()
|
||||||
|
{
|
||||||
|
applyModemConfig();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool RadioInterface::init()
|
bool RadioInterface::init()
|
||||||
{
|
{
|
||||||
DEBUG_MSG("Starting meshradio init...\n");
|
DEBUG_MSG("Starting meshradio init...\n");
|
||||||
@@ -194,6 +205,8 @@ bool RadioInterface::init()
|
|||||||
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
|
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
|
||||||
// time.
|
// time.
|
||||||
|
|
||||||
|
applyModemConfig();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +319,7 @@ void RadioInterface::applyModemConfig()
|
|||||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
// 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());
|
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
||||||
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels;
|
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels;
|
||||||
freq = myRegion->freq + myRegion->spacing * channel_num;
|
freq = myRegion->freq + radioConfig.preferences.frequency_offset + myRegion->spacing * channel_num;
|
||||||
|
|
||||||
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
|
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->freq: %f\n", myRegion->freq);
|
||||||
|
|||||||
@@ -104,7 +104,11 @@ class RadioInterface
|
|||||||
virtual bool sleep() { return true; }
|
virtual bool sleep() { return true; }
|
||||||
|
|
||||||
/// Disable this interface (while disabled, no packets can be sent or received)
|
/// Disable this interface (while disabled, no packets can be sent or received)
|
||||||
void disable() { disabled = true; sleep(); }
|
void disable()
|
||||||
|
{
|
||||||
|
disabled = true;
|
||||||
|
sleep();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a packet (possibly by enquing in a private fifo). This routine will
|
* Send a packet (possibly by enquing in a private fifo). This routine will
|
||||||
@@ -126,7 +130,7 @@ class RadioInterface
|
|||||||
/// Apply any radio provisioning changes
|
/// Apply any radio provisioning changes
|
||||||
/// Make sure the Driver is properly configured before calling init().
|
/// Make sure the Driver is properly configured before calling init().
|
||||||
/// \return true if initialisation succeeded.
|
/// \return true if initialisation succeeded.
|
||||||
virtual bool reconfigure() = 0;
|
virtual bool reconfigure();
|
||||||
|
|
||||||
/** The delay to use for retransmitting dropped packets */
|
/** The delay to use for retransmitting dropped packets */
|
||||||
uint32_t getRetransmissionMsec(const MeshPacket *p);
|
uint32_t getRetransmissionMsec(const MeshPacket *p);
|
||||||
@@ -174,13 +178,6 @@ class RadioInterface
|
|||||||
*/
|
*/
|
||||||
void limitPower();
|
void limitPower();
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert our modemConfig enum into wf, sf, etc...
|
|
||||||
*
|
|
||||||
* These paramaters will be pull from the channelSettings global
|
|
||||||
*/
|
|
||||||
virtual void applyModemConfig();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the frequency we selected for later reuse.
|
* Save the frequency we selected for later reuse.
|
||||||
*/
|
*/
|
||||||
@@ -192,6 +189,13 @@ class RadioInterface
|
|||||||
virtual void saveChannelNum(uint32_t savedChannelNum);
|
virtual void saveChannelNum(uint32_t savedChannelNum);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* Convert our modemConfig enum into wf, sf, etc...
|
||||||
|
*
|
||||||
|
* These paramaters will be pull from the channelSettings global
|
||||||
|
*/
|
||||||
|
void applyModemConfig();
|
||||||
|
|
||||||
/// Return 0 if sleep is okay
|
/// Return 0 if sleep is okay
|
||||||
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }
|
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }
|
||||||
|
|
||||||
@@ -208,18 +212,6 @@ class SimRadio : public RadioInterface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ErrorCode send(MeshPacket *p);
|
virtual ErrorCode send(MeshPacket *p);
|
||||||
|
|
||||||
// methods from radiohead
|
|
||||||
|
|
||||||
/// 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() { return true; }
|
|
||||||
|
|
||||||
/// Apply any radio provisioning changes
|
|
||||||
/// Make sure the Driver is properly configured before calling init().
|
|
||||||
/// \return true if initialisation succeeded.
|
|
||||||
virtual bool reconfigure() { return true; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Debug printing for packets
|
/// Debug printing for packets
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
|
|||||||
{
|
{
|
||||||
if (p->want_ack) {
|
if (p->want_ack) {
|
||||||
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
|
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
|
||||||
// message will rebroadcast
|
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop counts
|
||||||
|
// and we want this message to get through the whole mesh, so use the default.
|
||||||
if (p->to == NODENUM_BROADCAST && p->hop_limit == 0)
|
if (p->to == NODENUM_BROADCAST && p->hop_limit == 0)
|
||||||
p->hop_limit = 1;
|
p->hop_limit = HOP_RELIABLE;
|
||||||
|
|
||||||
auto copy = packetPool.allocCopy(*p);
|
auto copy = packetPool.allocCopy(*p);
|
||||||
startRetransmission(copy);
|
startRetransmission(copy);
|
||||||
@@ -34,11 +35,19 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
|||||||
// We are seeing someone rebroadcast one of our broadcast attempts.
|
// We are seeing someone rebroadcast one of our broadcast attempts.
|
||||||
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
|
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
|
||||||
// the original sending process.
|
// the original sending process.
|
||||||
if (stopRetransmission(getFrom(p), p->id)) {
|
|
||||||
|
// FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've heard one
|
||||||
|
// one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those nodes to reach
|
||||||
|
// our destination. Both of which might be incorrect.
|
||||||
|
auto key = GlobalPacketId(getFrom(p), p->id);
|
||||||
|
auto old = findPendingPacket(key);
|
||||||
|
if (old) {
|
||||||
DEBUG_MSG("generating implicit ack\n");
|
DEBUG_MSG("generating implicit ack\n");
|
||||||
// NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be
|
// NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be
|
||||||
// marked as wantAck
|
// marked as wantAck
|
||||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id);
|
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
|
||||||
|
|
||||||
|
stopRetransmission(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,9 +74,9 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
|||||||
// - not DSR routing)
|
// - not DSR routing)
|
||||||
if (p->want_ack) {
|
if (p->want_ack) {
|
||||||
if (MeshPlugin::currentReply)
|
if (MeshPlugin::currentReply)
|
||||||
DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack");
|
DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack\n");
|
||||||
else
|
else
|
||||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id);
|
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
|
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
|
||||||
@@ -166,7 +175,7 @@ int32_t ReliableRouter::doRetransmissions()
|
|||||||
if (p.numRetransmissions == 0) {
|
if (p.numRetransmissions == 0) {
|
||||||
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
|
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
|
||||||
p.packet->id);
|
p.packet->id);
|
||||||
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id);
|
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel);
|
||||||
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which
|
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which
|
||||||
// allows the DSR version to still be able to look at the PendingPacket
|
// allows the DSR version to still be able to look at the PendingPacket
|
||||||
stopRetransmission(it->first);
|
stopRetransmission(it->first);
|
||||||
|
|||||||
@@ -79,9 +79,10 @@ class ReliableRouter : public FloodingRouter
|
|||||||
/** Do our retransmission handling */
|
/** Do our retransmission handling */
|
||||||
virtual int32_t runOnce()
|
virtual int32_t runOnce()
|
||||||
{
|
{
|
||||||
auto d = FloodingRouter::runOnce();
|
// Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation
|
||||||
|
auto d = doRetransmissions();
|
||||||
|
|
||||||
int32_t r = doRetransmissions();
|
int32_t r = FloodingRouter::runOnce();
|
||||||
|
|
||||||
return min(d, r);
|
return min(d, r);
|
||||||
}
|
}
|
||||||
@@ -109,7 +110,6 @@ class ReliableRouter : public FloodingRouter
|
|||||||
PendingPacket *startRetransmission(MeshPacket *p);
|
PendingPacket *startRetransmission(MeshPacket *p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop any retransmissions we are doing of the specified node/packet ID pair
|
* Stop any retransmissions we are doing of the specified node/packet ID pair
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "plugins/RoutingPlugin.h"
|
#include "plugins/RoutingPlugin.h"
|
||||||
|
|
||||||
@@ -55,9 +56,11 @@ int32_t Router::runOnce()
|
|||||||
{
|
{
|
||||||
MeshPacket *mp;
|
MeshPacket *mp;
|
||||||
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) {
|
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) {
|
||||||
|
// printPacket("handle fromRadioQ", mp);
|
||||||
perhapsHandleReceived(mp);
|
perhapsHandleReceived(mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG_MSG("sleeping forever!\n");
|
||||||
return INT32_MAX; // Wait a long time - until we get woken for the message queue
|
return INT32_MAX; // Wait a long time - until we get woken for the message queue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,29 +106,36 @@ MeshPacket *Router::allocForSending()
|
|||||||
/**
|
/**
|
||||||
* Send an ack or a nak packet back towards whoever sent idFrom
|
* Send an ack or a nak packet back towards whoever sent idFrom
|
||||||
*/
|
*/
|
||||||
void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom)
|
void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||||
{
|
{
|
||||||
routingPlugin->sendAckNak(err, to, idFrom);
|
routingPlugin->sendAckNak(err, to, idFrom, chIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
||||||
{
|
{
|
||||||
DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err);
|
DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err);
|
||||||
sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id);
|
sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id, p->channel);
|
||||||
packetPool.release(p);
|
packetPool.release(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::setReceivedMessage() {
|
void Router::setReceivedMessage()
|
||||||
|
{
|
||||||
|
// DEBUG_MSG("set interval to ASAP\n");
|
||||||
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
|
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
|
||||||
|
runASAP = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode Router::sendLocal(MeshPacket *p)
|
ErrorCode Router::sendLocal(MeshPacket *p)
|
||||||
{
|
{
|
||||||
// No need to deliver externally if the destination is the local node
|
// No need to deliver externally if the destination is the local node
|
||||||
if (p->to == nodeDB.getNodeNum()) {
|
if (p->to == nodeDB.getNodeNum()) {
|
||||||
printPacket("Enqueuing local", p);
|
if (fromRadioQueue.enqueue(p, 0)) {
|
||||||
fromRadioQueue.enqueue(p);
|
printPacket("Enqueued local", p);
|
||||||
setReceivedMessage();
|
setReceivedMessage();
|
||||||
|
} else {
|
||||||
|
printPacket("BUG! fromRadioQueue is full! Discarding!", p);
|
||||||
|
packetPool.release(p);
|
||||||
|
}
|
||||||
return ERRNO_OK;
|
return ERRNO_OK;
|
||||||
} else if (!iface) {
|
} else if (!iface) {
|
||||||
// We must be sending to remote nodes also, fail if no interface found
|
// We must be sending to remote nodes also, fail if no interface found
|
||||||
@@ -143,9 +153,10 @@ ErrorCode Router::sendLocal(MeshPacket *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printBytes(const char *label, const uint8_t *p, size_t numbytes) {
|
void printBytes(const char *label, const uint8_t *p, size_t numbytes)
|
||||||
|
{
|
||||||
DEBUG_MSG("%s: ", label);
|
DEBUG_MSG("%s: ", label);
|
||||||
for(size_t i = 0; i < numbytes; i++)
|
for (size_t i = 0; i < numbytes; i++)
|
||||||
DEBUG_MSG("%02x ", p[i]);
|
DEBUG_MSG("%02x ", p[i]);
|
||||||
DEBUG_MSG("\n");
|
DEBUG_MSG("\n");
|
||||||
}
|
}
|
||||||
@@ -189,7 +200,7 @@ ErrorCode Router::send(MeshPacket *p)
|
|||||||
return ERRNO_TOO_LARGE;
|
return ERRNO_TOO_LARGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//printBytes("plaintext", bytes, numbytes);
|
// printBytes("plaintext", bytes, numbytes);
|
||||||
|
|
||||||
auto hash = channels.setActiveByIndex(p->channel);
|
auto hash = channels.setActiveByIndex(p->channel);
|
||||||
if (hash < 0) {
|
if (hash < 0) {
|
||||||
@@ -247,19 +258,18 @@ bool Router::perhapsDecode(MeshPacket *p)
|
|||||||
rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
|
rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
|
||||||
crypto->decrypt(p->from, p->id, rawSize, bytes);
|
crypto->decrypt(p->from, p->id, rawSize, bytes);
|
||||||
|
|
||||||
//printBytes("plaintext", bytes, p->encrypted.size);
|
// printBytes("plaintext", bytes, p->encrypted.size);
|
||||||
|
|
||||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||||
memset(&p->decoded, 0, sizeof(p->decoded));
|
memset(&p->decoded, 0, sizeof(p->decoded));
|
||||||
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
|
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
|
||||||
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
|
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
|
||||||
} else if(p->decoded.portnum == PortNum_UNKNOWN_APP) {
|
} else if (p->decoded.portnum == PortNum_UNKNOWN_APP) {
|
||||||
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
|
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// parsing was successful
|
// parsing was successful
|
||||||
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
|
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
|
||||||
p->channel = chIndex; // change to store the index instead of the hash
|
p->channel = chIndex; // change to store the index instead of the hash
|
||||||
printPacket("decoded message", p);
|
printPacket("decoded message", p);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -285,7 +295,7 @@ void Router::handleReceived(MeshPacket *p)
|
|||||||
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
||||||
|
|
||||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||||
bool decoded = perhapsDecode(p);
|
bool decoded = perhapsDecode(p);
|
||||||
if (decoded) {
|
if (decoded) {
|
||||||
// parsing was successful, queue for our recipient
|
// parsing was successful, queue for our recipient
|
||||||
printPacket("handleReceived", p);
|
printPacket("handleReceived", p);
|
||||||
@@ -293,18 +303,20 @@ void Router::handleReceived(MeshPacket *p)
|
|||||||
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
|
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
|
||||||
// sniffReceived(p);
|
// sniffReceived(p);
|
||||||
MeshPlugin::callPlugins(*p);
|
MeshPlugin::callPlugins(*p);
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("packet decoding failed\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::perhapsHandleReceived(MeshPacket *p)
|
void Router::perhapsHandleReceived(MeshPacket *p)
|
||||||
{
|
{
|
||||||
assert(radioConfig.has_preferences);
|
assert(radioConfig.has_preferences);
|
||||||
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, getFrom(p));
|
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, p->from);
|
||||||
|
|
||||||
if (ignore)
|
if (ignore)
|
||||||
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);
|
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);
|
||||||
else if (ignore |= shouldFilterReceived(p)) {
|
else if (ignore |= shouldFilterReceived(p)) {
|
||||||
// DEBUG_MSG("Incoming message was filtered 0x%x\n", p->from);
|
DEBUG_MSG("Incoming message was filtered 0x%x\n", p->from);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: we avoid calling shouldFilterReceived if we are supposed to ignore certain nodes - because some overrides might
|
// Note: we avoid calling shouldFilterReceived if we are supposed to ignore certain nodes - because some overrides might
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "PointerQueue.h"
|
#include "PointerQueue.h"
|
||||||
#include "RadioInterface.h"
|
#include "RadioInterface.h"
|
||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
|
#include "Channels.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mesh aware router that supports multiple interfaces.
|
* A mesh aware router that supports multiple interfaces.
|
||||||
@@ -106,7 +107,7 @@ class Router : protected concurrency::OSThread
|
|||||||
/**
|
/**
|
||||||
* Send an ack or a nak packet back towards whoever sent idFrom
|
* Send an ack or a nak packet back towards whoever sent idFrom
|
||||||
*/
|
*/
|
||||||
void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom);
|
void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ bool SX1262Interface::init()
|
|||||||
pinMode(SX1262_POWER_EN, OUTPUT);
|
pinMode(SX1262_POWER_EN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RadioLibInterface::init();
|
|
||||||
|
|
||||||
#ifdef SX1262_RXEN // set not rx or tx mode
|
#ifdef SX1262_RXEN // set not rx or tx mode
|
||||||
digitalWrite(SX1262_RXEN, LOW); // Set low before becoming an output
|
digitalWrite(SX1262_RXEN, LOW); // Set low before becoming an output
|
||||||
pinMode(SX1262_RXEN, OUTPUT);
|
pinMode(SX1262_RXEN, OUTPUT);
|
||||||
@@ -37,12 +35,12 @@ bool SX1262Interface::init()
|
|||||||
#ifndef SX1262_E22
|
#ifndef SX1262_E22
|
||||||
float tcxoVoltage = 0; // None - we use an XTAL
|
float tcxoVoltage = 0; // None - we use an XTAL
|
||||||
#else
|
#else
|
||||||
float tcxoVoltage =
|
// Use DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
|
||||||
1.8; // E22 uses DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
|
float tcxoVoltage = 1.8;
|
||||||
#endif
|
#endif
|
||||||
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
|
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
|
||||||
|
|
||||||
applyModemConfig();
|
RadioLibInterface::init();
|
||||||
|
|
||||||
if (power == 0)
|
if (power == 0)
|
||||||
power = SX1262_MAX_POWER;
|
power = SX1262_MAX_POWER;
|
||||||
@@ -72,20 +70,23 @@ bool SX1262Interface::init()
|
|||||||
|
|
||||||
bool SX1262Interface::reconfigure()
|
bool SX1262Interface::reconfigure()
|
||||||
{
|
{
|
||||||
applyModemConfig();
|
RadioLibInterface::reconfigure();
|
||||||
|
|
||||||
// set mode to standby
|
// set mode to standby
|
||||||
setStandby();
|
setStandby();
|
||||||
|
|
||||||
// configure publicly accessible settings
|
// configure publicly accessible settings
|
||||||
int err = lora.setSpreadingFactor(sf);
|
int err = lora.setSpreadingFactor(sf);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
err = lora.setBandwidth(bw);
|
err = lora.setBandwidth(bw);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
err = lora.setCodingRate(cr);
|
err = lora.setCodingRate(cr);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
|
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
|
||||||
err = lora.setRxGain(true);
|
err = lora.setRxGain(true);
|
||||||
@@ -101,7 +102,8 @@ bool SX1262Interface::reconfigure()
|
|||||||
assert(err == ERR_NONE);
|
assert(err == ERR_NONE);
|
||||||
|
|
||||||
err = lora.setFrequency(freq);
|
err = lora.setFrequency(freq);
|
||||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
if (err != ERR_NONE)
|
||||||
|
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||||
|
|
||||||
if (power > 22) // This chip has lower power limits than some
|
if (power > 22) // This chip has lower power limits than some
|
||||||
power = 22;
|
power = 22;
|
||||||
@@ -142,6 +144,7 @@ void SX1262Interface::addReceiveMetadata(MeshPacket *mp)
|
|||||||
{
|
{
|
||||||
// DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
|
// DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
|
||||||
mp->rx_snr = lora.getSNR();
|
mp->rx_snr = lora.getSNR();
|
||||||
|
mp->rx_rssi = lround(lora.getRSSI());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** We override to turn on transmitter power as needed.
|
/** We override to turn on transmitter power as needed.
|
||||||
|
|||||||
@@ -5,48 +5,62 @@
|
|||||||
#define START2 0xc3
|
#define START2 0xc3
|
||||||
#define HEADER_LEN 4
|
#define HEADER_LEN 4
|
||||||
|
|
||||||
void StreamAPI::loop()
|
int32_t StreamAPI::runOnce()
|
||||||
{
|
{
|
||||||
|
auto result = readStream();
|
||||||
writeStream();
|
writeStream();
|
||||||
readStream();
|
|
||||||
checkConnectionTimeout();
|
checkConnectionTimeout();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read any rx chars from the link and call handleToRadio
|
* Read any rx chars from the link and call handleToRadio
|
||||||
*/
|
*/
|
||||||
void StreamAPI::readStream()
|
int32_t StreamAPI::readStream()
|
||||||
{
|
{
|
||||||
while (stream->available()) { // Currently we never want to block
|
uint32_t now = millis();
|
||||||
uint8_t c = stream->read();
|
if (!stream->available()) {
|
||||||
|
// Nothing available this time, if the computer has talked to us recently, poll often, otherwise let CPU sleep a long time
|
||||||
|
bool recentRx = (now - lastRxMsec) < 2000;
|
||||||
|
return recentRx ? 5 : 250;
|
||||||
|
} else {
|
||||||
|
while (stream->available()) { // Currently we never want to block
|
||||||
|
uint8_t c = stream->read();
|
||||||
|
|
||||||
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
|
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
|
||||||
size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
|
size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
|
||||||
|
|
||||||
rxBuf[ptr] = c; // store all bytes (including framing)
|
rxBuf[ptr] = c; // store all bytes (including framing)
|
||||||
|
|
||||||
if (ptr == 0) { // looking for START1
|
if (ptr == 0) { // looking for START1
|
||||||
if (c != START1)
|
if (c != START1)
|
||||||
rxPtr = 0; // failed to find framing
|
rxPtr = 0; // failed to find framing
|
||||||
} else if (ptr == 1) { // looking for START2
|
} else if (ptr == 1) { // looking for START2
|
||||||
if (c != START2)
|
if (c != START2)
|
||||||
rxPtr = 0; // failed to find framing
|
rxPtr = 0; // failed to find framing
|
||||||
} else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
|
} else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
|
||||||
uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
|
uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
|
||||||
|
|
||||||
if (ptr == HEADER_LEN) {
|
if (ptr == HEADER_LEN) {
|
||||||
// we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
|
// we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
|
||||||
// protobuf also)
|
// protobuf also)
|
||||||
if (len > MAX_TO_FROM_RADIO_SIZE)
|
if (len > MAX_TO_FROM_RADIO_SIZE)
|
||||||
rxPtr = 0; // length is bogus, restart search for framing
|
rxPtr = 0; // length is bogus, restart search for framing
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
|
if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
|
||||||
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
rxPtr = 0; // start over again on the next packet
|
||||||
handleToRadio(rxBuf + HEADER_LEN, len);
|
|
||||||
rxPtr = 0; // start over again
|
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
||||||
|
if (handleToRadio(rxBuf + HEADER_LEN, len))
|
||||||
|
return 0; // we want to be called again ASAP because we still have more work to do
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we had packets available this time, so assume we might have them next time also
|
||||||
|
lastRxMsec = now;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,12 +85,18 @@ void StreamAPI::writeStream()
|
|||||||
void StreamAPI::emitTxBuffer(size_t len)
|
void StreamAPI::emitTxBuffer(size_t len)
|
||||||
{
|
{
|
||||||
if (len != 0) {
|
if (len != 0) {
|
||||||
|
// DEBUG_MSG("emit tx %d\n", len);
|
||||||
txBuf[0] = START1;
|
txBuf[0] = START1;
|
||||||
txBuf[1] = START2;
|
txBuf[1] = START2;
|
||||||
txBuf[2] = (len >> 8) & 0xff;
|
txBuf[2] = (len >> 8) & 0xff;
|
||||||
txBuf[3] = len & 0xff;
|
txBuf[3] = len & 0xff;
|
||||||
|
|
||||||
stream->write(txBuf, len + HEADER_LEN);
|
auto totalLen = len + HEADER_LEN;
|
||||||
|
stream->write(txBuf, totalLen);
|
||||||
|
/* for(size_t i = 0; i < totalLen; i++) {
|
||||||
|
stream->write(txBuf[i]);
|
||||||
|
// stream->flush();
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +107,6 @@ void StreamAPI::emitRebooted()
|
|||||||
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
|
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
|
||||||
fromRadioScratch.rebooted = true;
|
fromRadioScratch.rebooted = true;
|
||||||
|
|
||||||
DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "PhoneAPI.h"
|
#include "PhoneAPI.h"
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
|
||||||
// A To/FromRadio packet + our 32 bit header
|
// A To/FromRadio packet + our 32 bit header
|
||||||
#define MAX_STREAM_BUF_SIZE (MAX_TO_FROM_RADIO_SIZE + sizeof(uint32_t))
|
#define MAX_STREAM_BUF_SIZE (MAX_TO_FROM_RADIO_SIZE + sizeof(uint32_t))
|
||||||
@@ -27,7 +28,7 @@ valid utf8 encoding. This makes it a bit easier to start a device outputting reg
|
|||||||
after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding.
|
after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
class StreamAPI : public PhoneAPI
|
class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The stream we read/write from
|
* The stream we read/write from
|
||||||
@@ -37,21 +38,23 @@ class StreamAPI : public PhoneAPI
|
|||||||
uint8_t rxBuf[MAX_STREAM_BUF_SIZE];
|
uint8_t rxBuf[MAX_STREAM_BUF_SIZE];
|
||||||
size_t rxPtr = 0;
|
size_t rxPtr = 0;
|
||||||
|
|
||||||
|
/// time of last rx, used, to slow down our polling if we haven't heard from anyone
|
||||||
|
uint32_t lastRxMsec = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StreamAPI(Stream *_stream) : stream(_stream) {}
|
StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
|
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
|
||||||
* phone.
|
* phone.
|
||||||
* FIXME, to support better power behavior instead move to a thread and block on serial reads.
|
|
||||||
*/
|
*/
|
||||||
void loop();
|
virtual int32_t runOnce();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Read any rx chars from the link and call handleToRadio
|
* Read any rx chars from the link and call handleToRadio
|
||||||
*/
|
*/
|
||||||
void readStream();
|
int32_t readStream();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* call getFromRadio() and deliver encapsulated packets to the Stream
|
* call getFromRadio() and deliver encapsulated packets to the Stream
|
||||||
@@ -63,7 +66,7 @@ class StreamAPI : public PhoneAPI
|
|||||||
* Send a FromRadio.rebooted = true packet to the phone
|
* Send a FromRadio.rebooted = true packet to the phone
|
||||||
*/
|
*/
|
||||||
void emitRebooted();
|
void emitRebooted();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the current txBuffer over our stream
|
* Send the current txBuffer over our stream
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ template <class T> class TypedQueue
|
|||||||
|
|
||||||
bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; }
|
bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; }
|
||||||
|
|
||||||
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY)
|
/** euqueue a packet. Also, maxWait used to default to portMAX_DELAY, but we now want to callers to THINK about what blocking
|
||||||
|
* they want */
|
||||||
|
bool enqueue(T x, TickType_t maxWait)
|
||||||
{
|
{
|
||||||
if (reader) {
|
if (reader) {
|
||||||
reader->setInterval(0);
|
reader->setInterval(0);
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ typedef struct _AdminMessage {
|
|||||||
RadioConfig get_radio_response;
|
RadioConfig get_radio_response;
|
||||||
uint32_t get_channel_request;
|
uint32_t get_channel_request;
|
||||||
Channel get_channel_response;
|
Channel get_channel_response;
|
||||||
|
bool confirm_set_channel;
|
||||||
|
bool confirm_set_radio;
|
||||||
|
bool exit_simulator;
|
||||||
|
int32_t reboot_seconds;
|
||||||
};
|
};
|
||||||
} AdminMessage;
|
} AdminMessage;
|
||||||
|
|
||||||
@@ -43,6 +47,10 @@ extern "C" {
|
|||||||
#define AdminMessage_get_radio_response_tag 5
|
#define AdminMessage_get_radio_response_tag 5
|
||||||
#define AdminMessage_get_channel_request_tag 6
|
#define AdminMessage_get_channel_request_tag 6
|
||||||
#define AdminMessage_get_channel_response_tag 7
|
#define AdminMessage_get_channel_response_tag 7
|
||||||
|
#define AdminMessage_confirm_set_channel_tag 32
|
||||||
|
#define AdminMessage_confirm_set_radio_tag 33
|
||||||
|
#define AdminMessage_exit_simulator_tag 34
|
||||||
|
#define AdminMessage_reboot_seconds_tag 35
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
#define AdminMessage_FIELDLIST(X, a) \
|
#define AdminMessage_FIELDLIST(X, a) \
|
||||||
@@ -52,7 +60,11 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) \
|
|||||||
X(a, STATIC, ONEOF, BOOL, (variant,get_radio_request,get_radio_request), 4) \
|
X(a, STATIC, ONEOF, BOOL, (variant,get_radio_request,get_radio_request), 4) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_response), 5) \
|
X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_response), 5) \
|
||||||
X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \
|
X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7)
|
X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) \
|
||||||
|
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_channel), 32) \
|
||||||
|
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \
|
||||||
|
X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \
|
||||||
|
X(a, STATIC, ONEOF, INT32, (variant,reboot_seconds,reboot_seconds), 35)
|
||||||
#define AdminMessage_CALLBACK NULL
|
#define AdminMessage_CALLBACK NULL
|
||||||
#define AdminMessage_DEFAULT NULL
|
#define AdminMessage_DEFAULT NULL
|
||||||
#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig
|
#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig
|
||||||
@@ -67,7 +79,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
|
|||||||
#define AdminMessage_fields &AdminMessage_msg
|
#define AdminMessage_fields &AdminMessage_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define AdminMessage_size 351
|
#define AdminMessage_size 360
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ typedef struct _ChannelSettings {
|
|||||||
} ChannelSettings;
|
} ChannelSettings;
|
||||||
|
|
||||||
typedef struct _Channel {
|
typedef struct _Channel {
|
||||||
uint8_t index;
|
int8_t index;
|
||||||
bool has_settings;
|
bool has_settings;
|
||||||
ChannelSettings settings;
|
ChannelSettings settings;
|
||||||
Channel_Role role;
|
Channel_Role role;
|
||||||
@@ -100,7 +100,7 @@ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17)
|
|||||||
#define ChannelSettings_DEFAULT NULL
|
#define ChannelSettings_DEFAULT NULL
|
||||||
|
|
||||||
#define Channel_FIELDLIST(X, a) \
|
#define Channel_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, index, 1) \
|
X(a, STATIC, SINGULAR, INT32, index, 1) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, settings, 2) \
|
X(a, STATIC, OPTIONAL, MESSAGE, settings, 2) \
|
||||||
X(a, STATIC, SINGULAR, UENUM, role, 3)
|
X(a, STATIC, SINGULAR, UENUM, role, 3)
|
||||||
#define Channel_CALLBACK NULL
|
#define Channel_CALLBACK NULL
|
||||||
@@ -116,7 +116,7 @@ extern const pb_msgdesc_t Channel_msg;
|
|||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define ChannelSettings_size 87
|
#define ChannelSettings_size 87
|
||||||
#define Channel_size 94
|
#define Channel_size 102
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -6,7 +6,16 @@
|
|||||||
#error Regenerate this file with the current version of nanopb generator.
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
PB_BIND(LegacyRadioConfig, LegacyRadioConfig, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(LegacyRadioConfig_LegacyPreferences, LegacyRadioConfig_LegacyPreferences, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(DeviceState, DeviceState, 2)
|
PB_BIND(DeviceState, DeviceState, 2)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(ChannelFile, ChannelFile, 2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,17 +5,31 @@
|
|||||||
#define PB_DEVICEONLY_PB_H_INCLUDED
|
#define PB_DEVICEONLY_PB_H_INCLUDED
|
||||||
#include <pb.h>
|
#include <pb.h>
|
||||||
#include "mesh.pb.h"
|
#include "mesh.pb.h"
|
||||||
#include "radioconfig.pb.h"
|
|
||||||
#include "channel.pb.h"
|
#include "channel.pb.h"
|
||||||
|
#include "radioconfig.pb.h"
|
||||||
|
|
||||||
#if PB_PROTO_HEADER_VERSION != 40
|
#if PB_PROTO_HEADER_VERSION != 40
|
||||||
#error Regenerate this file with the current version of nanopb generator.
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Struct definitions */
|
/* Struct definitions */
|
||||||
|
typedef struct _ChannelFile {
|
||||||
|
pb_size_t channels_count;
|
||||||
|
Channel channels[8];
|
||||||
|
} ChannelFile;
|
||||||
|
|
||||||
|
typedef struct _LegacyRadioConfig_LegacyPreferences {
|
||||||
|
RegionCode region;
|
||||||
|
} LegacyRadioConfig_LegacyPreferences;
|
||||||
|
|
||||||
|
typedef struct _LegacyRadioConfig {
|
||||||
|
bool has_preferences;
|
||||||
|
LegacyRadioConfig_LegacyPreferences preferences;
|
||||||
|
} LegacyRadioConfig;
|
||||||
|
|
||||||
typedef struct _DeviceState {
|
typedef struct _DeviceState {
|
||||||
bool has_radio;
|
bool has_legacyRadio;
|
||||||
RadioConfig radio;
|
LegacyRadioConfig legacyRadio;
|
||||||
bool has_my_node;
|
bool has_my_node;
|
||||||
MyNodeInfo my_node;
|
MyNodeInfo my_node;
|
||||||
bool has_owner;
|
bool has_owner;
|
||||||
@@ -29,8 +43,6 @@ typedef struct _DeviceState {
|
|||||||
uint32_t version;
|
uint32_t version;
|
||||||
bool no_save;
|
bool no_save;
|
||||||
bool did_gps_reset;
|
bool did_gps_reset;
|
||||||
pb_size_t channels_count;
|
|
||||||
Channel channels[8];
|
|
||||||
} DeviceState;
|
} DeviceState;
|
||||||
|
|
||||||
|
|
||||||
@@ -39,11 +51,20 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Initializer values for message structs */
|
/* Initializer values for message structs */
|
||||||
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}}
|
#define LegacyRadioConfig_init_default {false, LegacyRadioConfig_LegacyPreferences_init_default}
|
||||||
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}}
|
#define LegacyRadioConfig_LegacyPreferences_init_default {_RegionCode_MIN}
|
||||||
|
#define DeviceState_init_default {false, LegacyRadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
|
||||||
|
#define ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}}
|
||||||
|
#define LegacyRadioConfig_init_zero {false, LegacyRadioConfig_LegacyPreferences_init_zero}
|
||||||
|
#define LegacyRadioConfig_LegacyPreferences_init_zero {_RegionCode_MIN}
|
||||||
|
#define DeviceState_init_zero {false, LegacyRadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
|
||||||
|
#define ChannelFile_init_zero {0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}}
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
#define DeviceState_radio_tag 1
|
#define ChannelFile_channels_tag 1
|
||||||
|
#define LegacyRadioConfig_LegacyPreferences_region_tag 15
|
||||||
|
#define LegacyRadioConfig_preferences_tag 1
|
||||||
|
#define DeviceState_legacyRadio_tag 1
|
||||||
#define DeviceState_my_node_tag 2
|
#define DeviceState_my_node_tag 2
|
||||||
#define DeviceState_owner_tag 3
|
#define DeviceState_owner_tag 3
|
||||||
#define DeviceState_node_db_tag 4
|
#define DeviceState_node_db_tag 4
|
||||||
@@ -52,11 +73,21 @@ extern "C" {
|
|||||||
#define DeviceState_version_tag 8
|
#define DeviceState_version_tag 8
|
||||||
#define DeviceState_no_save_tag 9
|
#define DeviceState_no_save_tag 9
|
||||||
#define DeviceState_did_gps_reset_tag 11
|
#define DeviceState_did_gps_reset_tag 11
|
||||||
#define DeviceState_channels_tag 13
|
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
|
#define LegacyRadioConfig_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1)
|
||||||
|
#define LegacyRadioConfig_CALLBACK NULL
|
||||||
|
#define LegacyRadioConfig_DEFAULT NULL
|
||||||
|
#define LegacyRadioConfig_preferences_MSGTYPE LegacyRadioConfig_LegacyPreferences
|
||||||
|
|
||||||
|
#define LegacyRadioConfig_LegacyPreferences_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, UENUM, region, 15)
|
||||||
|
#define LegacyRadioConfig_LegacyPreferences_CALLBACK NULL
|
||||||
|
#define LegacyRadioConfig_LegacyPreferences_DEFAULT NULL
|
||||||
|
|
||||||
#define DeviceState_FIELDLIST(X, a) \
|
#define DeviceState_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, radio, 1) \
|
X(a, STATIC, OPTIONAL, MESSAGE, legacyRadio, 1) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \
|
X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \
|
X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \
|
||||||
X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
|
X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
|
||||||
@@ -64,25 +95,38 @@ X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \
|
|||||||
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
|
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
|
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \
|
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11)
|
||||||
X(a, STATIC, REPEATED, MESSAGE, channels, 13)
|
|
||||||
#define DeviceState_CALLBACK NULL
|
#define DeviceState_CALLBACK NULL
|
||||||
#define DeviceState_DEFAULT NULL
|
#define DeviceState_DEFAULT NULL
|
||||||
#define DeviceState_radio_MSGTYPE RadioConfig
|
#define DeviceState_legacyRadio_MSGTYPE LegacyRadioConfig
|
||||||
#define DeviceState_my_node_MSGTYPE MyNodeInfo
|
#define DeviceState_my_node_MSGTYPE MyNodeInfo
|
||||||
#define DeviceState_owner_MSGTYPE User
|
#define DeviceState_owner_MSGTYPE User
|
||||||
#define DeviceState_node_db_MSGTYPE NodeInfo
|
#define DeviceState_node_db_MSGTYPE NodeInfo
|
||||||
#define DeviceState_receive_queue_MSGTYPE MeshPacket
|
#define DeviceState_receive_queue_MSGTYPE MeshPacket
|
||||||
#define DeviceState_rx_text_message_MSGTYPE MeshPacket
|
#define DeviceState_rx_text_message_MSGTYPE MeshPacket
|
||||||
#define DeviceState_channels_MSGTYPE Channel
|
|
||||||
|
|
||||||
|
#define ChannelFile_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, REPEATED, MESSAGE, channels, 1)
|
||||||
|
#define ChannelFile_CALLBACK NULL
|
||||||
|
#define ChannelFile_DEFAULT NULL
|
||||||
|
#define ChannelFile_channels_MSGTYPE Channel
|
||||||
|
|
||||||
|
extern const pb_msgdesc_t LegacyRadioConfig_msg;
|
||||||
|
extern const pb_msgdesc_t LegacyRadioConfig_LegacyPreferences_msg;
|
||||||
extern const pb_msgdesc_t DeviceState_msg;
|
extern const pb_msgdesc_t DeviceState_msg;
|
||||||
|
extern const pb_msgdesc_t ChannelFile_msg;
|
||||||
|
|
||||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||||
|
#define LegacyRadioConfig_fields &LegacyRadioConfig_msg
|
||||||
|
#define LegacyRadioConfig_LegacyPreferences_fields &LegacyRadioConfig_LegacyPreferences_msg
|
||||||
#define DeviceState_fields &DeviceState_msg
|
#define DeviceState_fields &DeviceState_msg
|
||||||
|
#define ChannelFile_fields &ChannelFile_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define DeviceState_size 6169
|
#define LegacyRadioConfig_size 4
|
||||||
|
#define LegacyRadioConfig_LegacyPreferences_size 2
|
||||||
|
#define DeviceState_size 5118
|
||||||
|
#define ChannelFile_size 832
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -45,3 +45,4 @@ PB_BIND(ToRadio, ToRadio, 2)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,25 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Enum definitions */
|
/* Enum definitions */
|
||||||
|
typedef enum _HardwareModel {
|
||||||
|
HardwareModel_UNSET = 0,
|
||||||
|
HardwareModel_TLORA_V2 = 1,
|
||||||
|
HardwareModel_TLORA_V1 = 2,
|
||||||
|
HardwareModel_TLORA_V2_1_1p6 = 3,
|
||||||
|
HardwareModel_TBEAM = 4,
|
||||||
|
HardwareModel_HELTEC = 5,
|
||||||
|
HardwareModel_TBEAM0p7 = 6,
|
||||||
|
HardwareModel_T_ECHO = 7,
|
||||||
|
HardwareModel_TLORA_V1_1p3 = 8,
|
||||||
|
HardwareModel_LORA_RELAY_V1 = 32,
|
||||||
|
HardwareModel_NRF52840DK = 33,
|
||||||
|
HardwareModel_PPR = 34,
|
||||||
|
HardwareModel_GENIEBLOCKS = 35,
|
||||||
|
HardwareModel_NRF52_UNKNOWN = 36,
|
||||||
|
HardwareModel_PORTDUINO = 37,
|
||||||
|
HardwareModel_ANDROID_SIM = 38
|
||||||
|
} HardwareModel;
|
||||||
|
|
||||||
typedef enum _Constants {
|
typedef enum _Constants {
|
||||||
Constants_Unused = 0,
|
Constants_Unused = 0,
|
||||||
Constants_DATA_PAYLOAD_LEN = 240
|
Constants_DATA_PAYLOAD_LEN = 240
|
||||||
@@ -25,7 +44,8 @@ typedef enum _CriticalErrorCode {
|
|||||||
CriticalErrorCode_UBloxInitFailed = 5,
|
CriticalErrorCode_UBloxInitFailed = 5,
|
||||||
CriticalErrorCode_NoAXP192 = 6,
|
CriticalErrorCode_NoAXP192 = 6,
|
||||||
CriticalErrorCode_InvalidRadioSetting = 7,
|
CriticalErrorCode_InvalidRadioSetting = 7,
|
||||||
CriticalErrorCode_TransmitFailed = 8
|
CriticalErrorCode_TransmitFailed = 8,
|
||||||
|
CriticalErrorCode_Brownout = 9
|
||||||
} CriticalErrorCode;
|
} CriticalErrorCode;
|
||||||
|
|
||||||
typedef enum _Routing_Error {
|
typedef enum _Routing_Error {
|
||||||
@@ -36,7 +56,10 @@ typedef enum _Routing_Error {
|
|||||||
Routing_Error_NO_INTERFACE = 4,
|
Routing_Error_NO_INTERFACE = 4,
|
||||||
Routing_Error_MAX_RETRANSMIT = 5,
|
Routing_Error_MAX_RETRANSMIT = 5,
|
||||||
Routing_Error_NO_CHANNEL = 6,
|
Routing_Error_NO_CHANNEL = 6,
|
||||||
Routing_Error_TOO_LARGE = 7
|
Routing_Error_TOO_LARGE = 7,
|
||||||
|
Routing_Error_NO_RESPONSE = 8,
|
||||||
|
Routing_Error_BAD_REQUEST = 32,
|
||||||
|
Routing_Error_NOT_AUTHORIZED = 33
|
||||||
} Routing_Error;
|
} Routing_Error;
|
||||||
|
|
||||||
typedef enum _MeshPacket_Priority {
|
typedef enum _MeshPacket_Priority {
|
||||||
@@ -82,11 +105,12 @@ typedef struct _MyNodeInfo {
|
|||||||
bool has_gps;
|
bool has_gps;
|
||||||
uint32_t num_bands;
|
uint32_t num_bands;
|
||||||
char region[12];
|
char region[12];
|
||||||
char hw_model[16];
|
char hw_model_deprecated[16];
|
||||||
char firmware_version[12];
|
char firmware_version[12];
|
||||||
CriticalErrorCode error_code;
|
CriticalErrorCode error_code;
|
||||||
uint32_t error_address;
|
uint32_t error_address;
|
||||||
uint32_t error_count;
|
uint32_t error_count;
|
||||||
|
uint32_t reboot_count;
|
||||||
uint32_t message_timeout_msec;
|
uint32_t message_timeout_msec;
|
||||||
uint32_t min_app_version;
|
uint32_t min_app_version;
|
||||||
uint32_t max_channels;
|
uint32_t max_channels;
|
||||||
@@ -110,6 +134,7 @@ typedef struct _User {
|
|||||||
char long_name[40];
|
char long_name[40];
|
||||||
char short_name[5];
|
char short_name[5];
|
||||||
pb_byte_t macaddr[6];
|
pb_byte_t macaddr[6];
|
||||||
|
HardwareModel hw_model;
|
||||||
} User;
|
} User;
|
||||||
|
|
||||||
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
|
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
|
||||||
@@ -128,6 +153,7 @@ typedef struct _MeshPacket {
|
|||||||
uint8_t hop_limit;
|
uint8_t hop_limit;
|
||||||
bool want_ack;
|
bool want_ack;
|
||||||
MeshPacket_Priority priority;
|
MeshPacket_Priority priority;
|
||||||
|
int32_t rx_rssi;
|
||||||
} MeshPacket;
|
} MeshPacket;
|
||||||
|
|
||||||
typedef struct _NodeInfo {
|
typedef struct _NodeInfo {
|
||||||
@@ -136,7 +162,7 @@ typedef struct _NodeInfo {
|
|||||||
User user;
|
User user;
|
||||||
bool has_position;
|
bool has_position;
|
||||||
Position position;
|
Position position;
|
||||||
uint32_t next_hop;
|
uint32_t last_heard;
|
||||||
float snr;
|
float snr;
|
||||||
} NodeInfo;
|
} NodeInfo;
|
||||||
|
|
||||||
@@ -167,22 +193,27 @@ typedef struct _ToRadio {
|
|||||||
union {
|
union {
|
||||||
MeshPacket packet;
|
MeshPacket packet;
|
||||||
uint32_t want_config_id;
|
uint32_t want_config_id;
|
||||||
|
bool disconnect;
|
||||||
};
|
};
|
||||||
} ToRadio;
|
} ToRadio;
|
||||||
|
|
||||||
|
|
||||||
/* Helper constants for enums */
|
/* Helper constants for enums */
|
||||||
|
#define _HardwareModel_MIN HardwareModel_UNSET
|
||||||
|
#define _HardwareModel_MAX HardwareModel_ANDROID_SIM
|
||||||
|
#define _HardwareModel_ARRAYSIZE ((HardwareModel)(HardwareModel_ANDROID_SIM+1))
|
||||||
|
|
||||||
#define _Constants_MIN Constants_Unused
|
#define _Constants_MIN Constants_Unused
|
||||||
#define _Constants_MAX Constants_DATA_PAYLOAD_LEN
|
#define _Constants_MAX Constants_DATA_PAYLOAD_LEN
|
||||||
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
|
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
|
||||||
|
|
||||||
#define _CriticalErrorCode_MIN CriticalErrorCode_None
|
#define _CriticalErrorCode_MIN CriticalErrorCode_None
|
||||||
#define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed
|
#define _CriticalErrorCode_MAX CriticalErrorCode_Brownout
|
||||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1))
|
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_Brownout+1))
|
||||||
|
|
||||||
#define _Routing_Error_MIN Routing_Error_NONE
|
#define _Routing_Error_MIN Routing_Error_NONE
|
||||||
#define _Routing_Error_MAX Routing_Error_TOO_LARGE
|
#define _Routing_Error_MAX Routing_Error_NOT_AUTHORIZED
|
||||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_TOO_LARGE+1))
|
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_NOT_AUTHORIZED+1))
|
||||||
|
|
||||||
#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET
|
#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET
|
||||||
#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX
|
#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX
|
||||||
@@ -199,24 +230,24 @@ extern "C" {
|
|||||||
|
|
||||||
/* Initializer values for message structs */
|
/* Initializer values for message structs */
|
||||||
#define Position_init_default {0, 0, 0, 0, 0}
|
#define Position_init_default {0, 0, 0, 0, 0}
|
||||||
#define User_init_default {"", "", "", {0}}
|
#define User_init_default {"", "", "", {0}, _HardwareModel_MIN}
|
||||||
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||||
#define Routing_init_default {0, {RouteDiscovery_init_default}}
|
#define Routing_init_default {0, {RouteDiscovery_init_default}}
|
||||||
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
||||||
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
|
||||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0}
|
||||||
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
||||||
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
|
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
|
||||||
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
||||||
#define Position_init_zero {0, 0, 0, 0, 0}
|
#define Position_init_zero {0, 0, 0, 0, 0}
|
||||||
#define User_init_zero {"", "", "", {0}}
|
#define User_init_zero {"", "", "", {0}, _HardwareModel_MIN}
|
||||||
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||||
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
|
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
|
||||||
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
||||||
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
|
||||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0}
|
||||||
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||||
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
|
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
|
||||||
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
||||||
@@ -236,11 +267,12 @@ extern "C" {
|
|||||||
#define MyNodeInfo_has_gps_tag 2
|
#define MyNodeInfo_has_gps_tag 2
|
||||||
#define MyNodeInfo_num_bands_tag 3
|
#define MyNodeInfo_num_bands_tag 3
|
||||||
#define MyNodeInfo_region_tag 4
|
#define MyNodeInfo_region_tag 4
|
||||||
#define MyNodeInfo_hw_model_tag 5
|
#define MyNodeInfo_hw_model_deprecated_tag 5
|
||||||
#define MyNodeInfo_firmware_version_tag 6
|
#define MyNodeInfo_firmware_version_tag 6
|
||||||
#define MyNodeInfo_error_code_tag 7
|
#define MyNodeInfo_error_code_tag 7
|
||||||
#define MyNodeInfo_error_address_tag 8
|
#define MyNodeInfo_error_address_tag 8
|
||||||
#define MyNodeInfo_error_count_tag 9
|
#define MyNodeInfo_error_count_tag 9
|
||||||
|
#define MyNodeInfo_reboot_count_tag 10
|
||||||
#define MyNodeInfo_message_timeout_msec_tag 13
|
#define MyNodeInfo_message_timeout_msec_tag 13
|
||||||
#define MyNodeInfo_min_app_version_tag 14
|
#define MyNodeInfo_min_app_version_tag 14
|
||||||
#define MyNodeInfo_max_channels_tag 15
|
#define MyNodeInfo_max_channels_tag 15
|
||||||
@@ -254,6 +286,7 @@ extern "C" {
|
|||||||
#define User_long_name_tag 2
|
#define User_long_name_tag 2
|
||||||
#define User_short_name_tag 3
|
#define User_short_name_tag 3
|
||||||
#define User_macaddr_tag 4
|
#define User_macaddr_tag 4
|
||||||
|
#define User_hw_model_tag 6
|
||||||
#define MeshPacket_from_tag 1
|
#define MeshPacket_from_tag 1
|
||||||
#define MeshPacket_to_tag 2
|
#define MeshPacket_to_tag 2
|
||||||
#define MeshPacket_channel_tag 3
|
#define MeshPacket_channel_tag 3
|
||||||
@@ -265,10 +298,11 @@ extern "C" {
|
|||||||
#define MeshPacket_hop_limit_tag 10
|
#define MeshPacket_hop_limit_tag 10
|
||||||
#define MeshPacket_want_ack_tag 11
|
#define MeshPacket_want_ack_tag 11
|
||||||
#define MeshPacket_priority_tag 12
|
#define MeshPacket_priority_tag 12
|
||||||
|
#define MeshPacket_rx_rssi_tag 13
|
||||||
#define NodeInfo_num_tag 1
|
#define NodeInfo_num_tag 1
|
||||||
#define NodeInfo_user_tag 2
|
#define NodeInfo_user_tag 2
|
||||||
#define NodeInfo_position_tag 3
|
#define NodeInfo_position_tag 3
|
||||||
#define NodeInfo_next_hop_tag 5
|
#define NodeInfo_last_heard_tag 4
|
||||||
#define NodeInfo_snr_tag 7
|
#define NodeInfo_snr_tag 7
|
||||||
#define Routing_route_request_tag 1
|
#define Routing_route_request_tag 1
|
||||||
#define Routing_route_reply_tag 2
|
#define Routing_route_reply_tag 2
|
||||||
@@ -282,6 +316,7 @@ extern "C" {
|
|||||||
#define FromRadio_packet_tag 11
|
#define FromRadio_packet_tag 11
|
||||||
#define ToRadio_packet_tag 2
|
#define ToRadio_packet_tag 2
|
||||||
#define ToRadio_want_config_id_tag 100
|
#define ToRadio_want_config_id_tag 100
|
||||||
|
#define ToRadio_disconnect_tag 104
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
#define Position_FIELDLIST(X, a) \
|
#define Position_FIELDLIST(X, a) \
|
||||||
@@ -297,7 +332,8 @@ X(a, STATIC, SINGULAR, FIXED32, time, 9)
|
|||||||
X(a, STATIC, SINGULAR, STRING, id, 1) \
|
X(a, STATIC, SINGULAR, STRING, id, 1) \
|
||||||
X(a, STATIC, SINGULAR, STRING, long_name, 2) \
|
X(a, STATIC, SINGULAR, STRING, long_name, 2) \
|
||||||
X(a, STATIC, SINGULAR, STRING, short_name, 3) \
|
X(a, STATIC, SINGULAR, STRING, short_name, 3) \
|
||||||
X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4)
|
X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) \
|
||||||
|
X(a, STATIC, SINGULAR, UENUM, hw_model, 6)
|
||||||
#define User_CALLBACK NULL
|
#define User_CALLBACK NULL
|
||||||
#define User_DEFAULT NULL
|
#define User_DEFAULT NULL
|
||||||
|
|
||||||
@@ -336,7 +372,8 @@ X(a, STATIC, SINGULAR, FIXED32, rx_time, 7) \
|
|||||||
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 8) \
|
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 8) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \
|
X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \
|
X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \
|
||||||
X(a, STATIC, SINGULAR, UENUM, priority, 12)
|
X(a, STATIC, SINGULAR, UENUM, priority, 12) \
|
||||||
|
X(a, STATIC, SINGULAR, INT32, rx_rssi, 13)
|
||||||
#define MeshPacket_CALLBACK NULL
|
#define MeshPacket_CALLBACK NULL
|
||||||
#define MeshPacket_DEFAULT NULL
|
#define MeshPacket_DEFAULT NULL
|
||||||
#define MeshPacket_payloadVariant_decoded_MSGTYPE Data
|
#define MeshPacket_payloadVariant_decoded_MSGTYPE Data
|
||||||
@@ -345,7 +382,7 @@ X(a, STATIC, SINGULAR, UENUM, priority, 12)
|
|||||||
X(a, STATIC, SINGULAR, UINT32, num, 1) \
|
X(a, STATIC, SINGULAR, UINT32, num, 1) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \
|
X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
|
X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, next_hop, 5) \
|
X(a, STATIC, SINGULAR, FIXED32, last_heard, 4) \
|
||||||
X(a, STATIC, SINGULAR, FLOAT, snr, 7)
|
X(a, STATIC, SINGULAR, FLOAT, snr, 7)
|
||||||
#define NodeInfo_CALLBACK NULL
|
#define NodeInfo_CALLBACK NULL
|
||||||
#define NodeInfo_DEFAULT NULL
|
#define NodeInfo_DEFAULT NULL
|
||||||
@@ -357,11 +394,12 @@ X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
|
|||||||
X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \
|
X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, num_bands, 3) \
|
X(a, STATIC, SINGULAR, UINT32, num_bands, 3) \
|
||||||
X(a, STATIC, SINGULAR, STRING, region, 4) \
|
X(a, STATIC, SINGULAR, STRING, region, 4) \
|
||||||
X(a, STATIC, SINGULAR, STRING, hw_model, 5) \
|
X(a, STATIC, SINGULAR, STRING, hw_model_deprecated, 5) \
|
||||||
X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \
|
X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \
|
||||||
X(a, STATIC, SINGULAR, UENUM, error_code, 7) \
|
X(a, STATIC, SINGULAR, UENUM, error_code, 7) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, error_address, 8) \
|
X(a, STATIC, SINGULAR, UINT32, error_address, 8) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, error_count, 9) \
|
X(a, STATIC, SINGULAR, UINT32, error_count, 9) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, reboot_count, 10) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, message_timeout_msec, 13) \
|
X(a, STATIC, SINGULAR, UINT32, message_timeout_msec, 13) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, min_app_version, 14) \
|
X(a, STATIC, SINGULAR, UINT32, min_app_version, 14) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, max_channels, 15)
|
X(a, STATIC, SINGULAR, UINT32, max_channels, 15)
|
||||||
@@ -393,7 +431,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 11)
|
|||||||
|
|
||||||
#define ToRadio_FIELDLIST(X, a) \
|
#define ToRadio_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \
|
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \
|
||||||
X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100)
|
X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \
|
||||||
|
X(a, STATIC, ONEOF, BOOL, (payloadVariant,disconnect,disconnect), 104)
|
||||||
#define ToRadio_CALLBACK NULL
|
#define ToRadio_CALLBACK NULL
|
||||||
#define ToRadio_DEFAULT NULL
|
#define ToRadio_DEFAULT NULL
|
||||||
#define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket
|
#define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket
|
||||||
@@ -425,16 +464,16 @@ extern const pb_msgdesc_t ToRadio_msg;
|
|||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define Position_size 37
|
#define Position_size 37
|
||||||
#define User_size 72
|
#define User_size 74
|
||||||
#define RouteDiscovery_size 40
|
#define RouteDiscovery_size 40
|
||||||
#define Routing_size 42
|
#define Routing_size 42
|
||||||
#define Data_size 260
|
#define Data_size 260
|
||||||
#define MeshPacket_size 298
|
#define MeshPacket_size 309
|
||||||
#define NodeInfo_size 130
|
#define NodeInfo_size 131
|
||||||
#define MyNodeInfo_size 89
|
#define MyNodeInfo_size 95
|
||||||
#define LogRecord_size 81
|
#define LogRecord_size 81
|
||||||
#define FromRadio_size 307
|
#define FromRadio_size 318
|
||||||
#define ToRadio_size 301
|
#define ToRadio_size 312
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ typedef struct _RadioConfig_UserPreferences {
|
|||||||
bool is_router;
|
bool is_router;
|
||||||
bool is_low_power;
|
bool is_low_power;
|
||||||
bool fixed_position;
|
bool fixed_position;
|
||||||
|
bool serial_disabled;
|
||||||
|
float frequency_offset;
|
||||||
bool factory_reset;
|
bool factory_reset;
|
||||||
bool debug_log_enabled;
|
bool debug_log_enabled;
|
||||||
pb_size_t ignore_incoming_count;
|
pb_size_t ignore_incoming_count;
|
||||||
@@ -104,7 +106,6 @@ typedef struct _RadioConfig_UserPreferences {
|
|||||||
bool range_test_plugin_enabled;
|
bool range_test_plugin_enabled;
|
||||||
uint32_t range_test_plugin_sender;
|
uint32_t range_test_plugin_sender;
|
||||||
bool range_test_plugin_save;
|
bool range_test_plugin_save;
|
||||||
bool store_forward_plugin_enabled;
|
|
||||||
uint32_t store_forward_plugin_records;
|
uint32_t store_forward_plugin_records;
|
||||||
bool environmental_measurement_plugin_measurement_enabled;
|
bool environmental_measurement_plugin_measurement_enabled;
|
||||||
bool environmental_measurement_plugin_screen_enabled;
|
bool environmental_measurement_plugin_screen_enabled;
|
||||||
@@ -114,6 +115,7 @@ typedef struct _RadioConfig_UserPreferences {
|
|||||||
bool environmental_measurement_plugin_display_farenheit;
|
bool environmental_measurement_plugin_display_farenheit;
|
||||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type;
|
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type;
|
||||||
uint32_t environmental_measurement_plugin_sensor_pin;
|
uint32_t environmental_measurement_plugin_sensor_pin;
|
||||||
|
bool store_forward_plugin_enabled;
|
||||||
} RadioConfig_UserPreferences;
|
} RadioConfig_UserPreferences;
|
||||||
|
|
||||||
typedef struct _RadioConfig {
|
typedef struct _RadioConfig {
|
||||||
@@ -150,9 +152,9 @@ extern "C" {
|
|||||||
|
|
||||||
/* Initializer values for message structs */
|
/* Initializer values for message structs */
|
||||||
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
|
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
|
||||||
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0}
|
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
|
||||||
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
|
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
|
||||||
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0}
|
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
||||||
@@ -177,6 +179,8 @@ extern "C" {
|
|||||||
#define RadioConfig_UserPreferences_is_router_tag 37
|
#define RadioConfig_UserPreferences_is_router_tag 37
|
||||||
#define RadioConfig_UserPreferences_is_low_power_tag 38
|
#define RadioConfig_UserPreferences_is_low_power_tag 38
|
||||||
#define RadioConfig_UserPreferences_fixed_position_tag 39
|
#define RadioConfig_UserPreferences_fixed_position_tag 39
|
||||||
|
#define RadioConfig_UserPreferences_serial_disabled_tag 40
|
||||||
|
#define RadioConfig_UserPreferences_frequency_offset_tag 41
|
||||||
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
||||||
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
|
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
|
||||||
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
|
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
|
||||||
@@ -195,7 +199,6 @@ extern "C" {
|
|||||||
#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132
|
#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132
|
||||||
#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133
|
#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133
|
||||||
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
|
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
|
||||||
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136
|
|
||||||
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
|
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
|
||||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140
|
||||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141
|
||||||
@@ -205,6 +208,7 @@ extern "C" {
|
|||||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_display_farenheit_tag 145
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_display_farenheit_tag 145
|
||||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146
|
||||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147
|
||||||
|
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 148
|
||||||
#define RadioConfig_preferences_tag 1
|
#define RadioConfig_preferences_tag 1
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
@@ -237,6 +241,8 @@ X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
|
|||||||
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
|
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
|
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
|
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, serial_disabled, 40) \
|
||||||
|
X(a, STATIC, SINGULAR, FLOAT, frequency_offset, 41) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
|
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
|
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
|
||||||
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
|
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
|
||||||
@@ -255,7 +261,6 @@ X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \
|
|||||||
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \
|
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
|
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
|
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \
|
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \
|
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
|
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
|
||||||
@@ -264,7 +269,8 @@ X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_inter
|
|||||||
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) \
|
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \
|
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \
|
||||||
X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \
|
X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147)
|
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 148)
|
||||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||||
#define RadioConfig_UserPreferences_DEFAULT NULL
|
#define RadioConfig_UserPreferences_DEFAULT NULL
|
||||||
|
|
||||||
@@ -276,8 +282,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
|
|||||||
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
|
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define RadioConfig_size 348
|
#define RadioConfig_size 357
|
||||||
#define RadioConfig_UserPreferences_size 345
|
#define RadioConfig_UserPreferences_size 354
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
|
#include "RadioLibInterface.h"
|
||||||
#include "airtime.h"
|
#include "airtime.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh/http/ContentHelper.h"
|
#include "mesh/http/ContentHelper.h"
|
||||||
@@ -11,7 +12,6 @@
|
|||||||
#include <HTTPMultipartBodyParser.hpp>
|
#include <HTTPMultipartBodyParser.hpp>
|
||||||
#include <HTTPURLEncodedBodyParser.hpp>
|
#include <HTTPURLEncodedBodyParser.hpp>
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
#include "RadioLibInterface.h"
|
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
@@ -77,7 +77,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
|||||||
ResourceNode *nodeAPIv1ToRadio = new ResourceNode("/api/v1/toradio", "PUT", &handleAPIv1ToRadio);
|
ResourceNode *nodeAPIv1ToRadio = new ResourceNode("/api/v1/toradio", "PUT", &handleAPIv1ToRadio);
|
||||||
ResourceNode *nodeAPIv1FromRadio = new ResourceNode("/api/v1/fromradio", "GET", &handleAPIv1FromRadio);
|
ResourceNode *nodeAPIv1FromRadio = new ResourceNode("/api/v1/fromradio", "GET", &handleAPIv1FromRadio);
|
||||||
|
|
||||||
ResourceNode *nodeHotspot = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot);
|
ResourceNode *nodeHotspotApple = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot);
|
||||||
|
ResourceNode *nodeHotspotAndroid = new ResourceNode("/generate_204", "GET", &handleHotspot);
|
||||||
ResourceNode *nodeFavicon = new ResourceNode("/favicon.ico", "GET", &handleFavicon);
|
ResourceNode *nodeFavicon = new ResourceNode("/favicon.ico", "GET", &handleFavicon);
|
||||||
ResourceNode *nodeRoot = new ResourceNode("/", "GET", &handleRoot);
|
ResourceNode *nodeRoot = new ResourceNode("/", "GET", &handleRoot);
|
||||||
ResourceNode *nodeStaticBrowse = new ResourceNode("/static", "GET", &handleStaticBrowse);
|
ResourceNode *nodeStaticBrowse = new ResourceNode("/static", "GET", &handleStaticBrowse);
|
||||||
@@ -96,7 +97,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
|||||||
secureServer->registerNode(nodeAPIv1ToRadioOptions);
|
secureServer->registerNode(nodeAPIv1ToRadioOptions);
|
||||||
secureServer->registerNode(nodeAPIv1ToRadio);
|
secureServer->registerNode(nodeAPIv1ToRadio);
|
||||||
secureServer->registerNode(nodeAPIv1FromRadio);
|
secureServer->registerNode(nodeAPIv1FromRadio);
|
||||||
secureServer->registerNode(nodeHotspot);
|
secureServer->registerNode(nodeHotspotApple);
|
||||||
|
secureServer->registerNode(nodeHotspotAndroid);
|
||||||
secureServer->registerNode(nodeFavicon);
|
secureServer->registerNode(nodeFavicon);
|
||||||
secureServer->registerNode(nodeRoot);
|
secureServer->registerNode(nodeRoot);
|
||||||
secureServer->registerNode(nodeStaticBrowse);
|
secureServer->registerNode(nodeStaticBrowse);
|
||||||
@@ -117,7 +119,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
|||||||
insecureServer->registerNode(nodeAPIv1ToRadioOptions);
|
insecureServer->registerNode(nodeAPIv1ToRadioOptions);
|
||||||
insecureServer->registerNode(nodeAPIv1ToRadio);
|
insecureServer->registerNode(nodeAPIv1ToRadio);
|
||||||
insecureServer->registerNode(nodeAPIv1FromRadio);
|
insecureServer->registerNode(nodeAPIv1FromRadio);
|
||||||
insecureServer->registerNode(nodeHotspot);
|
insecureServer->registerNode(nodeHotspotApple);
|
||||||
|
insecureServer->registerNode(nodeHotspotAndroid);
|
||||||
insecureServer->registerNode(nodeFavicon);
|
insecureServer->registerNode(nodeFavicon);
|
||||||
insecureServer->registerNode(nodeRoot);
|
insecureServer->registerNode(nodeRoot);
|
||||||
insecureServer->registerNode(nodeStaticBrowse);
|
insecureServer->registerNode(nodeStaticBrowse);
|
||||||
@@ -931,6 +934,10 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
|||||||
res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging()));
|
res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging()));
|
||||||
res->println("},");
|
res->println("},");
|
||||||
|
|
||||||
|
res->println("\"device\": {");
|
||||||
|
res->printf("\"reboot_counter\": %d\n", myNodeInfo.reboot_count);
|
||||||
|
res->println("},");
|
||||||
|
|
||||||
res->println("\"radio\": {");
|
res->println("\"radio\": {");
|
||||||
res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq());
|
res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq());
|
||||||
res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum());
|
res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum());
|
||||||
@@ -938,8 +945,6 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
res->println("},");
|
res->println("},");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
res->println("\"status\": \"ok\"");
|
res->println("\"status\": \"ok\"");
|
||||||
res->println("}");
|
res->println("}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ static void WiFiEvent(WiFiEvent_t event);
|
|||||||
// DNS Server for the Captive Portal
|
// DNS Server for the Captive Portal
|
||||||
DNSServer dnsServer;
|
DNSServer dnsServer;
|
||||||
|
|
||||||
static WiFiServerPort *apiPort;
|
|
||||||
|
|
||||||
uint8_t wifiDisconnectReason = 0;
|
uint8_t wifiDisconnectReason = 0;
|
||||||
|
|
||||||
// Stores our hostname
|
// Stores our hostname
|
||||||
@@ -180,14 +178,7 @@ void initWifi(bool forceSoftAP)
|
|||||||
DEBUG_MSG("Not using WIFI\n");
|
DEBUG_MSG("Not using WIFI\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initApiServer()
|
|
||||||
{
|
|
||||||
// Start API server on port 4403
|
|
||||||
if (!apiPort) {
|
|
||||||
apiPort = new WiFiServerPort();
|
|
||||||
apiPort->init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the Espressif SDK to
|
// Called by the Espressif SDK to
|
||||||
static void WiFiEvent(WiFiEvent_t event)
|
static void WiFiEvent(WiFiEvent_t event)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0]))
|
#define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0]))
|
||||||
|
|
||||||
/// Max number of channels allowed
|
/// Max number of channels allowed
|
||||||
#define MAX_NUM_CHANNELS (member_size(DeviceState, channels) / member_size(DeviceState, channels[0]))
|
#define MAX_NUM_CHANNELS (member_size(ChannelFile, channels) / member_size(ChannelFile, channels[0]))
|
||||||
|
|
||||||
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
|
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
|
||||||
/// returns the encoded packet size
|
/// returns the encoded packet size
|
||||||
|
|||||||
@@ -3,6 +3,17 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
static WiFiServerPort *apiPort;
|
||||||
|
|
||||||
|
void initApiServer()
|
||||||
|
{
|
||||||
|
// Start API server on port 4403
|
||||||
|
if (!apiPort) {
|
||||||
|
apiPort = new WiFiServerPort();
|
||||||
|
apiPort->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
|
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
|
||||||
{
|
{
|
||||||
DEBUG_MSG("Incoming wifi connection\n");
|
DEBUG_MSG("Incoming wifi connection\n");
|
||||||
@@ -29,18 +40,20 @@ void WiFiServerAPI::onConnectionChanged(bool connected)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// override close to also shutdown the TCP link
|
/// override close to also shutdown the TCP link
|
||||||
void WiFiServerAPI::close() {
|
void WiFiServerAPI::close()
|
||||||
|
{
|
||||||
client.stop(); // drop tcp connection
|
client.stop(); // drop tcp connection
|
||||||
StreamAPI::close();
|
StreamAPI::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WiFiServerAPI::loop()
|
int32_t WiFiServerAPI::runOnce()
|
||||||
{
|
{
|
||||||
if (client.connected()) {
|
if (client.connected()) {
|
||||||
StreamAPI::loop();
|
return StreamAPI::runOnce();
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
DEBUG_MSG("Client dropped connection, suspending API service\n");
|
||||||
|
enabled = false; // we no longer need to run
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +63,7 @@ WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM), concurrency::
|
|||||||
|
|
||||||
void WiFiServerPort::init()
|
void WiFiServerPort::init()
|
||||||
{
|
{
|
||||||
DEBUG_MSG("API server sistening on TCP port %d\n", MESHTASTIC_PORTNUM);
|
DEBUG_MSG("API server listening on TCP port %d\n", MESHTASTIC_PORTNUM);
|
||||||
begin();
|
begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,18 +80,5 @@ int32_t WiFiServerPort::runOnce()
|
|||||||
openAPI = new WiFiServerAPI(client);
|
openAPI = new WiFiServerAPI(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openAPI) {
|
return 100; // only check occasionally for incoming connections
|
||||||
// Allow idle processing so the API can read from its incoming stream
|
|
||||||
if(!openAPI->loop()) {
|
|
||||||
// If our API link was up, shut it down
|
|
||||||
|
|
||||||
DEBUG_MSG("Client dropped connection, closing API client\n");
|
|
||||||
// Note: we can't call delete here because this object includes other state
|
|
||||||
// besides the stream API. Instead kill it later when we start a new instance
|
|
||||||
delete openAPI;
|
|
||||||
openAPI = NULL;
|
|
||||||
}
|
|
||||||
return 0; // run fast while our API server is running
|
|
||||||
} else
|
|
||||||
return 100; // only check occasionally for incoming connections
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "StreamAPI.h"
|
#include "StreamAPI.h"
|
||||||
#include "concurrency/OSThread.h"
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,15 +17,14 @@ class WiFiServerAPI : public StreamAPI
|
|||||||
|
|
||||||
virtual ~WiFiServerAPI();
|
virtual ~WiFiServerAPI();
|
||||||
|
|
||||||
/// @return true if we want to keep running, or false if we are ready to be destroyed
|
|
||||||
virtual bool loop(); // Check for dropped client connections
|
|
||||||
|
|
||||||
/// override close to also shutdown the TCP link
|
/// override close to also shutdown the TCP link
|
||||||
virtual void close();
|
virtual void close();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Hookable to find out when connection changes
|
/// Hookable to find out when connection changes
|
||||||
virtual void onConnectionChanged(bool connected);
|
virtual void onConnectionChanged(bool connected);
|
||||||
|
|
||||||
|
virtual int32_t runOnce(); // Check for dropped client connections
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,3 +46,5 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
|
|||||||
|
|
||||||
int32_t runOnce();
|
int32_t runOnce();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void initApiServer();
|
||||||
|
|||||||
@@ -487,7 +487,6 @@ void reinitBluetooth()
|
|||||||
DEBUG_MSG("Starting bluetooth\n");
|
DEBUG_MSG("Starting bluetooth\n");
|
||||||
if (isFirstTime) {
|
if (isFirstTime) {
|
||||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||||
bluetoothPhoneAPI->init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME - if waking from light sleep, only esp_nimble_hci_init?
|
// FIXME - if waking from light sleep, only esp_nimble_hci_init?
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
#include "BluetoothCommon.h"
|
#include "BluetoothCommon.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "mesh/PhoneAPI.h"
|
||||||
|
#include "mesh/mesh-pb-constants.h"
|
||||||
#include <bluefruit.h>
|
#include <bluefruit.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
|
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
|
||||||
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
|
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
|
||||||
static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
|
static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
|
||||||
@@ -155,7 +155,6 @@ void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt
|
|||||||
void setupMeshService(void)
|
void setupMeshService(void)
|
||||||
{
|
{
|
||||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||||
bluetoothPhoneAPI->init();
|
|
||||||
|
|
||||||
meshBleService.begin();
|
meshBleService.begin();
|
||||||
|
|
||||||
@@ -213,6 +212,7 @@ void NRF52Bluetooth::setup()
|
|||||||
{
|
{
|
||||||
// Initialise the Bluefruit module
|
// Initialise the Bluefruit module
|
||||||
DEBUG_MSG("Initialise the Bluefruit nRF52 module\n");
|
DEBUG_MSG("Initialise the Bluefruit nRF52 module\n");
|
||||||
|
Bluefruit.autoConnLed(false);
|
||||||
Bluefruit.begin();
|
Bluefruit.begin();
|
||||||
|
|
||||||
// Set the advertised device name (keep it short!)
|
// Set the advertised device name (keep it short!)
|
||||||
@@ -224,7 +224,8 @@ void NRF52Bluetooth::setup()
|
|||||||
|
|
||||||
// Configure and Start the Device Information Service
|
// Configure and Start the Device Information Service
|
||||||
DEBUG_MSG("Configuring the Device Information Service\n");
|
DEBUG_MSG("Configuring the Device Information Service\n");
|
||||||
bledis.setManufacturer(HW_VENDOR);
|
// FIXME, we should set a mfg string based on our HW_VENDOR enum
|
||||||
|
// bledis.setManufacturer(HW_VENDOR);
|
||||||
bledis.setModel(optstr(HW_VERSION));
|
bledis.setModel(optstr(HW_VERSION));
|
||||||
bledis.setFirmwareRev(optstr(APP_VERSION));
|
bledis.setFirmwareRev(optstr(APP_VERSION));
|
||||||
bledis.begin();
|
bledis.begin();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user