mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-25 20:20:26 +00:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fce95431e6 | ||
|
|
591a07c0fe | ||
|
|
c410f2d151 | ||
|
|
9502fa62e6 | ||
|
|
2a6480ec48 | ||
|
|
7c5ab885be | ||
|
|
21cfb151a8 | ||
|
|
84505b1717 | ||
|
|
d735e3006e | ||
|
|
af5d82dbde | ||
|
|
a97072eca0 | ||
|
|
cef6e248e7 | ||
|
|
b4c379f5fc | ||
|
|
1b8f41d353 | ||
|
|
449a3959b0 | ||
|
|
719a0c485b | ||
|
|
a4bbdc443f | ||
|
|
999afdf05e | ||
|
|
f492f6deb6 | ||
|
|
60f7ec8998 | ||
|
|
469d0ade72 | ||
|
|
1f33b03c30 | ||
|
|
351be2f327 | ||
|
|
3f401e8cac | ||
|
|
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 | ||
|
|
959b540c02 | ||
|
|
68781492ad | ||
|
|
590e147186 | ||
|
|
0b358674ff | ||
|
|
0df01f2586 | ||
|
|
ca23665463 | ||
|
|
f55ac8e9c9 | ||
|
|
6e37fe6343 | ||
|
|
217bd934d7 | ||
|
|
58715f454c | ||
|
|
772f2a15ff | ||
|
|
5b0d8381b9 | ||
|
|
d841d86bbc | ||
|
|
ecaae87b79 | ||
|
|
5835abbcf6 | ||
|
|
2f7c2a2aea | ||
|
|
87ec7b09aa | ||
|
|
f8ec072093 | ||
|
|
781d2f0ad6 | ||
|
|
7bbd2c0e80 | ||
|
|
315cfe4f2d | ||
|
|
707ed75138 | ||
|
|
c0e180759d | ||
|
|
6ceb423033 | ||
|
|
96c4286e7d | ||
|
|
f320ecbde8 | ||
|
|
d014ae0bff | ||
|
|
12a7934ca1 | ||
|
|
64bc791e48 | ||
|
|
1f33506962 | ||
|
|
ba9a94d026 | ||
|
|
6f13966d19 | ||
|
|
96cfad4e57 | ||
|
|
a26ebb1b69 | ||
|
|
7a764efc10 | ||
|
|
49b1f4c5af | ||
|
|
fbe56531d2 | ||
|
|
aa6b29a4b5 | ||
|
|
c88b9732eb | ||
|
|
2c29e8b179 | ||
|
|
d2d6b8e12f | ||
|
|
badfaa8545 | ||
|
|
c5b67d821d | ||
|
|
63bf7a29f3 | ||
|
|
845dd1f9e3 | ||
|
|
c9c44a934d | ||
|
|
2f6981a27f | ||
|
|
8739469db3 | ||
|
|
0c0c0babba | ||
|
|
950b32232f | ||
|
|
2f6034b067 | ||
|
|
159f7622e4 | ||
|
|
2cc2fa906a | ||
|
|
1b71a0f436 | ||
|
|
2af9e1431e | ||
|
|
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...
|
||||
- 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
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
23
.github/workflows/main.yml
vendored
23
.github/workflows/main.yml
vendored
@@ -7,17 +7,18 @@ jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Checkout submodules
|
||||
uses: textbook/git-checkout-submodule-action@master
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@master
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Install Platform IO
|
||||
- name: Install Platform IO and meshtastic-python
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
pip install -U platformio meshtastic
|
||||
- name: Install extra python tools
|
||||
run: |
|
||||
pip install -U adafruit-nrfutil
|
||||
@@ -30,5 +31,11 @@ jobs:
|
||||
run: platformio run -e heltec
|
||||
- name: Build for lora-relay-v1
|
||||
run: platformio run -e lora-relay-v1
|
||||
- name: Build for linux
|
||||
run: platformio run -e linux
|
||||
- name: Build for native
|
||||
run: platformio run -e native
|
||||
- name: Integration test
|
||||
run: |
|
||||
.pio/build/native/program &
|
||||
sleep 1
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -15,7 +15,8 @@ Thumbs.db
|
||||
.built
|
||||
.context
|
||||
.cproject
|
||||
.idea/*
|
||||
.vagrant
|
||||
nanopb*
|
||||
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>
|
||||
137
.idea/workspace.xml
generated
Normal file
137
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,137 @@
|
||||
<?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$/docs/software/TODO.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/software/TODO.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/proto" beforeDir="false" afterPath="$PROJECT_DIR$/proto" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/mesh/generated/mesh.pb.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/generated/mesh.pb.h" 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="ExecutionTargetManager" SELECTED_TARGET="CMakeBuildProfile:native" />
|
||||
<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="PlatformIO.PlatformIO Upload">
|
||||
<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="GradleAppRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.cpp.gradle.execution.GradleNativeBuildBeforeRunTaskProvider$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" />
|
||||
</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/StreamAPI.cpp</url>
|
||||
<line>20</line>
|
||||
<option name="timeStamp" value="4" />
|
||||
</line-breakpoint>
|
||||
<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>
|
||||
</breakpoints>
|
||||
</breakpoint-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
|
||||
// for the documentation about the extensions.json format
|
||||
"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"
|
||||
],
|
||||
"C_Cpp.dimInactiveRegions": true,
|
||||
"cmake.configureOnOpen": true,
|
||||
"protoc": {
|
||||
"compile_on_save": false,
|
||||
"compile_all_path": "/home/kevinh/development/meshtastic/meshtastic-esp32/proto",
|
||||
@@ -76,5 +77,6 @@
|
||||
"--java_out=/tmp",
|
||||
"-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
@@ -4,12 +4,6 @@ set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py`
|
||||
|
||||
# We now only do regionless builds
|
||||
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
|
||||
|
||||
@@ -30,26 +24,17 @@ mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal
|
||||
# build the named environment and copy the bins to the release directory
|
||||
function do_build() {
|
||||
BOARD=$1
|
||||
COUNTRY=$2
|
||||
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.*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
# Are we building a universal/regionless rom?
|
||||
if [ "x$COUNTRY" != "x" ]
|
||||
then
|
||||
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
|
||||
export HW_VERSION="1.0"
|
||||
basename=universal/firmware-$BOARD-$VERSION
|
||||
|
||||
pio run --environment $BOARD # -v
|
||||
SRCELF=.pio/build/$BOARD/firmware.elf
|
||||
@@ -71,10 +56,6 @@ function do_boards() {
|
||||
declare boards=$1
|
||||
declare isNrf=$2
|
||||
for board in $boards; do
|
||||
for country in $COUNTRIES; do
|
||||
do_build $board $country "$isNrf"
|
||||
done
|
||||
|
||||
# Build universal
|
||||
do_build $board "" "$isNrf"
|
||||
done
|
||||
|
||||
@@ -35,6 +35,8 @@ shift "$((OPTIND-1))"
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash update ${FILENAME}."
|
||||
esptool.py --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"
|
||||
esptool.py --baud 921600 erase_region 0xe000 0x2000
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
@@ -6,6 +6,8 @@ BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader
|
||||
|
||||
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
|
||||
# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000
|
||||
# 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
|
||||
|
||||
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
|
||||
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
|
||||
@@ -2,8 +2,32 @@
|
||||
|
||||
You probably don't care about this section - skip to the next one.
|
||||
|
||||
## before next release
|
||||
|
||||
* 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
|
||||
* test 1.2.10 firmware update on android
|
||||
* DONE test link sharing on android
|
||||
* luxon bug report - seeing rx acks for nodes that are not on the network
|
||||
* document how to do remote admin
|
||||
* release py, android, device
|
||||
|
||||
## 1.2 cleanup & 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
|
||||
* DONE move device types into an enum in nodeinfo
|
||||
* fix android to use new device types for firmware update
|
||||
|
||||
* 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 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
|
||||
@@ -21,32 +45,44 @@ You probably don't care about this section - skip to the next one.
|
||||
* DONE implement 'get channels' Admin plugin operation
|
||||
* DONE use get-channels from python
|
||||
* DONE use get channels & get settings from android
|
||||
* use set-channel from python
|
||||
* DONE use set-channel from python
|
||||
* DONE make settings changes from python work
|
||||
* DONE pthon should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
|
||||
* DONE add check for old devices with new API library
|
||||
* DONE release python api
|
||||
* DONE release protobufs
|
||||
* DONE release to developers
|
||||
* DONE fix setch-fast in python tool
|
||||
* turn off fault 8: https://github.com/meshtastic/Meshtastic-device/issues/734
|
||||
* age out pendingrequests in the python API
|
||||
* DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection
|
||||
* DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
|
||||
* DONE 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
|
||||
* warn in android app about unset regions
|
||||
* use set-channel from android
|
||||
* DONE test android channel setting
|
||||
* DONE release to users
|
||||
* DONE warn in android app about unset regions
|
||||
* DONE use set-channel from android
|
||||
* DONE add gui in android app for setting region
|
||||
* stress test channel download from python, sometimes it seems like we don't get all replies
|
||||
* investigate @mc-hamster report of heap corruption
|
||||
* DONE use set-user from android
|
||||
* combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
|
||||
* don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
|
||||
* use portuino TCP connection to debug with python API
|
||||
* 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
|
||||
* test remote info and remote settings changes
|
||||
* make python tests more exhaustive
|
||||
* 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)
|
||||
* stress test multi channel
|
||||
* pick default random admin key
|
||||
* exclude admin channels from 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...
|
||||
* use presence of gpio channel to enable gpio ops, same for serial etc...
|
||||
* pick default random admin key
|
||||
* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
|
||||
* add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
|
||||
* 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)
|
||||
* stress test multi channel
|
||||
* investigate @mc-hamster report of heap corruption
|
||||
* DONE use set-user from android
|
||||
* generalize the concept of "shortstrings" use it for both PSKs and well known channel names. Possibly use a ShortString class.
|
||||
* 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)
|
||||
* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
|
||||
* DONE warn in python api if we are too new to talk to the device code
|
||||
* DONE make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning.
|
||||
* DONE "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well"
|
||||
@@ -58,6 +94,7 @@ You probably don't care about this section - skip to the next one.
|
||||
* 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
|
||||
* 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 support for full DSR unicast delivery
|
||||
* DONE move acks into routing
|
||||
* DONE make all subpackets different versions of data
|
||||
@@ -72,21 +109,38 @@ You probably don't care about this section - skip to the next one.
|
||||
* DONE move setCrypto call into packet send and packet decode code
|
||||
* implement 'small location diffs' change
|
||||
* 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
|
||||
|
||||
eink:
|
||||
|
||||
* DONE check email of reported issues
|
||||
* DONE turn off vbus driving (in bootloader)
|
||||
* new battery level sensing
|
||||
* measure current draw
|
||||
* current draw no good
|
||||
* DONE: fix backlight
|
||||
* USB is busted because of power enable mode?
|
||||
* 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
|
||||
* usb doesn't stay connected
|
||||
* check GPS works
|
||||
* check GPS fast locking
|
||||
* 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
|
||||
|
||||
@@ -45,6 +45,18 @@ Recommended settings for a sender at different radio settings:
|
||||
Medium ... 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
|
||||
|
||||
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.
|
||||
|
||||
@@ -16,7 +16,8 @@ default_envs = tbeam
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = lora-relay-v1 # nrf board
|
||||
;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 is not currently used
|
||||
@@ -33,6 +34,8 @@ default_envs = tbeam
|
||||
extra_scripts = bin/platformio-custom.py
|
||||
|
||||
; 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
|
||||
build_flags = -Wno-missing-field-initializers
|
||||
-Wno-format
|
||||
@@ -40,14 +43,7 @@ build_flags = -Wno-missing-field-initializers
|
||||
-DHW_VERSION_${sysenv.COUNTRY}
|
||||
-DHW_VERSION=${sysenv.HW_VERSION}
|
||||
-DUSE_THREAD_NAMES
|
||||
-DTINYGPSPLUS_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
|
||||
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
|
||||
; the default is esptool
|
||||
; upload_protocol = esp-prog
|
||||
@@ -71,10 +67,10 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
|
||||
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
|
||||
https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
|
||||
https://github.com/meshtastic/arduino-fsm.git#55c47b6cded91645aff05a27b6e5821d8d0f64be
|
||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||
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
|
||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||
SPI
|
||||
@@ -115,6 +111,13 @@ lib_ignore = segger_rtt
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#352c8ea7cb73f10433ed139f34251979c470ad56
|
||||
|
||||
; 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
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
@@ -184,7 +187,6 @@ src_filter =
|
||||
; platform = nordicnrf52
|
||||
platform = https://github.com/meshtastic/platform-nordicnrf52.git#1a2639a6b0f79b5df66bea3e3089f0d5285fdc63
|
||||
extends = arduino_base
|
||||
debug_tool = jlink
|
||||
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)
|
||||
build_flags =
|
||||
@@ -198,6 +200,27 @@ lib_ignore =
|
||||
BluetoothOTA
|
||||
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 =
|
||||
source gdbinit
|
||||
|
||||
@@ -332,19 +355,20 @@ lib_deps =
|
||||
TFT_eSPI
|
||||
|
||||
; The Portduino based sim environment on top of linux
|
||||
[env:linux]
|
||||
platform = https://github.com/geeksville/platform-portduino.git
|
||||
[env:native]
|
||||
platform = https://github.com/geeksville/platform-native.git
|
||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
||||
build_flags = ${arduino_base.build_flags} -O0
|
||||
framework = arduino
|
||||
board = linux_x86_64
|
||||
board = native
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
rweather/Crypto
|
||||
|
||||
; The GenieBlocks LORA prototype board
|
||||
[env:genieblocks_lora]
|
||||
extends = esp32_base
|
||||
board = genieblocks_lora
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D GENIEBLOCKS
|
||||
; note: @geeksville disabled because genieblocks_lora is not checked into the boards directory, please send in a PR to add it ;-)
|
||||
;[env:genieblocks_lora]
|
||||
;extends = esp32_base
|
||||
;board = genieblocks_lora
|
||||
;build_flags =
|
||||
; ${esp32_base.build_flags} -D GENIEBLOCKS
|
||||
2
proto
2
proto
Submodule proto updated: 94bd0aae44...b8c0499f28
@@ -178,10 +178,11 @@ void PowerFSM_setup()
|
||||
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.
|
||||
2) If we detect USB power from the power management chip, we must be getting power externally.
|
||||
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 = (powerStatus && !powerStatus->getHasBattery()) || (!isLowPower && powerStatus && powerStatus->getHasUSB());
|
||||
bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||
|
||||
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
|
||||
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "RedirectablePrint.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
/**
|
||||
* A printer that doesn't go anywhere
|
||||
@@ -20,7 +20,7 @@ size_t RedirectablePrint::write(uint8_t c)
|
||||
{
|
||||
// Always send the characters to our segger JTAG debugger
|
||||
#ifdef SEGGER_STDOUT_CH
|
||||
SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c);
|
||||
SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c);
|
||||
#endif
|
||||
|
||||
dest->write(c);
|
||||
@@ -38,7 +38,7 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
va_end(arg);
|
||||
return 0;
|
||||
};
|
||||
if (len >= printBufLen) {
|
||||
if (len >= (int)printBufLen) {
|
||||
delete[] printBuf;
|
||||
printBufLen *= 2;
|
||||
printBuf = new char[printBufLen];
|
||||
@@ -55,45 +55,52 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
|
||||
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;
|
||||
|
||||
// If we are the first message on a report, include the header
|
||||
if (!isContinuationMessage) {
|
||||
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;
|
||||
if (!inDebugPrint) {
|
||||
inDebugPrint = true;
|
||||
|
||||
// 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
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
|
||||
r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
|
||||
} else
|
||||
r += printf("??:??:?? %u ", millis() / 1000);
|
||||
// Cope with 0 len format strings, but look for new line terminator
|
||||
bool hasNewline = *format && format[strlen(format) - 1] == '\n';
|
||||
|
||||
auto thread = concurrency::OSThread::currentThread;
|
||||
if(thread) {
|
||||
print("[");
|
||||
print(thread->ThreadName);
|
||||
print("] ");
|
||||
// If we are the first message on a report, include the header
|
||||
if (!isContinuationMessage) {
|
||||
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
|
||||
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;
|
||||
}
|
||||
@@ -19,6 +19,8 @@ class RedirectablePrint : public Print
|
||||
/// Used to allow multiple logDebug messages to appear on a single log line
|
||||
bool isContinuationMessage = false;
|
||||
|
||||
volatile bool inDebugPrint = false;
|
||||
|
||||
public:
|
||||
RedirectablePrint(Print *_dest) : dest(_dest) {}
|
||||
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
#include "SerialConsole.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include "NodeDB.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define Port Serial
|
||||
|
||||
SerialConsole console;
|
||||
|
||||
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)
|
||||
{
|
||||
canWrite = false; // We don't send packets to our port until it has talked to us first
|
||||
@@ -29,7 +37,7 @@ void SerialConsole::init()
|
||||
void 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
|
||||
if(!radioConfig.preferences.debug_log_enabled)
|
||||
if (!radioConfig.preferences.debug_log_enabled)
|
||||
setDestination(&noopPrint);
|
||||
canWrite = true;
|
||||
|
||||
|
||||
@@ -32,4 +32,7 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
};
|
||||
|
||||
// A simple wrapper to allow non class aware code write to the console
|
||||
void consolePrintf(const char *format, ...);
|
||||
|
||||
extern SerialConsole console;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "concurrency/BinarySemaphoreFreeRTOS.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
|
||||
@@ -9,6 +10,7 @@ namespace concurrency
|
||||
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS()
|
||||
{
|
||||
semaphore = xSemaphoreCreateBinary();
|
||||
assert(semaphore);
|
||||
}
|
||||
|
||||
BinarySemaphoreFreeRTOS::~BinarySemaphoreFreeRTOS()
|
||||
|
||||
@@ -163,7 +163,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#if defined(TBEAM_V10)
|
||||
// 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
|
||||
|
||||
@@ -204,7 +204,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(TBEAM_V07)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tbeam0.7"
|
||||
#define HW_VENDOR HardwareModel_TBEAM0p7
|
||||
|
||||
// #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)
|
||||
// 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.
|
||||
// Tested on Neo6m module.
|
||||
@@ -258,7 +258,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(TLORA_V1)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tlora-v1"
|
||||
#define HW_VENDOR HardwareModel_TLORA_V1
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#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)
|
||||
// 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_TX_PIN
|
||||
@@ -311,7 +311,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(TLORA_V1_3)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tlora-v1-3"
|
||||
#define HW_VENDOR HardwareModel_TLORA_V1p3
|
||||
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
@@ -338,7 +338,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(TLORA_V2_1_16)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tlora-v2-1-1.6"
|
||||
#define HW_VENDOR HardwareModel_TLORA_V2_1_1p6
|
||||
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
@@ -366,7 +366,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(GENIEBLOCKS)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "genieblocks"
|
||||
#define HW_VENDOR HardwareModel_GENIEBLOCKS
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#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 BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen -->
|
||||
//Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal
|
||||
//pull-ups or pull-down resistors.
|
||||
// Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal
|
||||
// pull-ups or pull-down resistors.
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 38 // a No connect on the SX1262 module
|
||||
@@ -399,7 +399,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifdef ARDUINO_NRF52840_PCA10056
|
||||
|
||||
// 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
|
||||
#undef LED_INVERTED
|
||||
@@ -407,15 +407,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(ARDUINO_NRF52840_PPR)
|
||||
|
||||
#define HW_VENDOR "ppr"
|
||||
#define HW_VENDOR HardwareModel_PPR
|
||||
|
||||
#elif NRF52_SERIES
|
||||
|
||||
#define HW_VENDOR "nrf52unknown" // FIXME - unknown nrf52 board
|
||||
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN
|
||||
|
||||
#elif PORTDUINO
|
||||
|
||||
#define HW_VENDOR "portduino"
|
||||
#define HW_VENDOR HardwareModel_PORTDUINO
|
||||
|
||||
#define USE_SIM_RADIO
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class ESP32CryptoEngine : public CryptoEngine
|
||||
static uint8_t scratch[MAX_BLOCKSIZE];
|
||||
size_t nc_off = 0;
|
||||
|
||||
// DEBUG_MSG("ESP32 encrypt!\n");
|
||||
// DEBUG_MSG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetNum, numBytes);
|
||||
initNonce(fromNode, packetNum);
|
||||
assert(numBytes <= MAX_BLOCKSIZE);
|
||||
memcpy(scratch, bytes, numBytes);
|
||||
|
||||
@@ -25,7 +25,7 @@ uint8_t GPS::i2cAddress = 0;
|
||||
|
||||
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.
|
||||
static bool didSerialInit;
|
||||
|
||||
@@ -33,7 +33,7 @@ bool GPS::setupGPS()
|
||||
{
|
||||
if (_serial_gps && !didSerialInit) {
|
||||
didSerialInit = true;
|
||||
|
||||
|
||||
#ifdef GPS_RX_PIN
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||
#else
|
||||
@@ -73,6 +73,13 @@ bool GPS::setup()
|
||||
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
|
||||
#ifndef GPS_WAKE_ACTIVE
|
||||
#define GPS_WAKE_ACTIVE 1
|
||||
@@ -86,8 +93,8 @@ void GPS::wake()
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void GPS::sleep() {
|
||||
void GPS::sleep()
|
||||
{
|
||||
#ifdef PIN_GPS_WAKE
|
||||
digitalWrite(PIN_GPS_WAKE, GPS_WAKE_ACTIVE ? 0 : 1);
|
||||
pinMode(PIN_GPS_WAKE, OUTPUT);
|
||||
@@ -158,7 +165,8 @@ uint32_t GPS::getWakeTime() const
|
||||
return t; // already maxint
|
||||
|
||||
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
|
||||
|
||||
@@ -179,8 +187,8 @@ uint32_t GPS::getSleepTime() const
|
||||
if (t == UINT32_MAX)
|
||||
return t; // already maxint
|
||||
|
||||
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
|
||||
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 *= 1000;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
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 */
|
||||
Observable<const meshtastic::GPSStatus *> newStatus;
|
||||
|
||||
@@ -143,11 +143,13 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
drawIconScreen(region, display, state, x, y);
|
||||
}
|
||||
|
||||
#ifdef HAS_EINK
|
||||
/// Used on eink displays while in deep sleep
|
||||
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
drawIconScreen("Sleeping...", display, state, x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -229,7 +231,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
displayedNodeNum = 0; // Not currently showing a node pane
|
||||
|
||||
MeshPacket &mp = devicestate.rx_text_message;
|
||||
NodeInfo *node = nodeDB.getNode(mp.from);
|
||||
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
|
||||
// DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from,
|
||||
// mp.decoded.variant.data.decoded.bytes);
|
||||
|
||||
@@ -791,7 +793,8 @@ void Screen::setup()
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
textMessageObserver.observe(textMessagePlugin);
|
||||
if(textMessagePlugin)
|
||||
textMessageObserver.observe(textMessagePlugin);
|
||||
}
|
||||
|
||||
void Screen::forceDisplay()
|
||||
@@ -849,7 +852,7 @@ int32_t Screen::runOnce()
|
||||
free(cmd.print_text);
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("BUG: invalid cmd");
|
||||
DEBUG_MSG("BUG: invalid cmd\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
src/main.cpp
21
src/main.cpp
@@ -32,6 +32,10 @@
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#endif
|
||||
|
||||
#ifdef PORTDUINO
|
||||
#include "mesh/wifi/WiFiServerAPI.h"
|
||||
#endif
|
||||
|
||||
#include "RF95Interface.h"
|
||||
#include "SX1262Interface.h"
|
||||
|
||||
@@ -279,7 +283,13 @@ void setup()
|
||||
concurrency::hasBeenSetup = true;
|
||||
|
||||
#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
|
||||
|
||||
#ifdef USE_SEGGER
|
||||
@@ -359,7 +369,7 @@ void setup()
|
||||
#endif
|
||||
|
||||
// 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
|
||||
// Don't init display if we don't have one or we are waking headless due to a timer event
|
||||
@@ -533,6 +543,10 @@ void setup()
|
||||
webServerThread = new WebServerThread();
|
||||
#endif
|
||||
|
||||
#ifdef PORTDUINO
|
||||
initApiServer();
|
||||
#endif
|
||||
|
||||
// Start airtime logger thread.
|
||||
airTime = new AirTime();
|
||||
|
||||
@@ -583,6 +597,9 @@ void loop()
|
||||
#ifndef NO_ESP32
|
||||
esp32Loop();
|
||||
#endif
|
||||
#ifdef NRF52_SERIES
|
||||
nrf52Loop();
|
||||
#endif
|
||||
|
||||
// For debugging
|
||||
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
|
||||
|
||||
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;
|
||||
|
||||
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 code = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
for (size_t i = 0; i < len; i++)
|
||||
code ^= p[i];
|
||||
return code;
|
||||
}
|
||||
@@ -161,8 +165,8 @@ int16_t Channels::setCrypto(ChannelIndex chIndex)
|
||||
|
||||
void Channels::initDefaults()
|
||||
{
|
||||
devicestate.channels_count = MAX_NUM_CHANNELS;
|
||||
for (int i = 0; i < devicestate.channels_count; i++)
|
||||
channelFile.channels_count = MAX_NUM_CHANNELS;
|
||||
for (int i = 0; i < channelFile.channels_count; i++)
|
||||
fixupChannel(i);
|
||||
initDefaultChannel(0);
|
||||
}
|
||||
@@ -170,7 +174,7 @@ void Channels::initDefaults()
|
||||
void Channels::onConfigChanged()
|
||||
{
|
||||
// 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);
|
||||
|
||||
if (ch.role == Channel_Role_PRIMARY)
|
||||
@@ -180,8 +184,8 @@ void Channels::onConfigChanged()
|
||||
|
||||
Channel &Channels::getByIndex(ChannelIndex chIndex)
|
||||
{
|
||||
assert(chIndex < devicestate.channels_count);
|
||||
Channel *ch = devicestate.channels + chIndex;
|
||||
assert(chIndex < channelFile.channels_count);
|
||||
Channel *ch = channelFile.channels + chIndex;
|
||||
return *ch;
|
||||
}
|
||||
|
||||
@@ -192,8 +196,8 @@ void Channels::setChannel(const Channel &c)
|
||||
// if this is the new primary, demote any existing roles
|
||||
if (c.role == Channel_Role_PRIMARY)
|
||||
for (int i = 0; i < getNumChannels(); i++)
|
||||
if (devicestate.channels[i].role == Channel_Role_PRIMARY)
|
||||
devicestate.channels[i].role = Channel_Role_SECONDARY;
|
||||
if (channelFile.channels[i].role == Channel_Role_PRIMARY)
|
||||
channelFile.channels[i].role = Channel_Role_SECONDARY;
|
||||
|
||||
old = c; // slam in the new settings/role
|
||||
}
|
||||
@@ -275,10 +279,11 @@ const char *Channels::getPrimaryName()
|
||||
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
|
||||
{
|
||||
if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
|
||||
DEBUG_MSG("Skipping channel %d due to invalid hash/index\n", chIndex);
|
||||
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex), channelHash);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
|
||||
setCrypto(chIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ class Channels
|
||||
int16_t hashes[MAX_NUM_CHANNELS];
|
||||
|
||||
public:
|
||||
|
||||
/// Well known channel names
|
||||
static const char *adminChannel, *gpioChannel, *serialChannel;
|
||||
|
||||
const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
|
||||
|
||||
/** Return the Channel for a specified index */
|
||||
@@ -44,7 +48,7 @@ class Channels
|
||||
/** The index of the primary channel */
|
||||
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
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
void CryptoEngine::setKey(const CryptoKey &k)
|
||||
{
|
||||
DEBUG_MSG("Installing AES%d key!\n", k.length * 8);
|
||||
/* for(uint8_t i = 0; i < k.length; i++)
|
||||
DEBUG_MSG("%02x ", k.bytes[i]);
|
||||
DEBUG_MSG("\n"); */
|
||||
|
||||
key = k;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
// ignore rebroadcasts.
|
||||
// this will also add records for any ACKs we receive for our messages
|
||||
if (p->to != NODENUM_BROADCAST || p->hop_limit != HOP_RELIABLE) {
|
||||
addRoute(p->from, p->from, 0); // We are adjacent with zero hops
|
||||
addRoute(getFrom(p), getFrom(p), 0); // We are adjacent with zero hops
|
||||
}
|
||||
|
||||
if (c)
|
||||
|
||||
@@ -31,7 +31,7 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
{
|
||||
// If a broadcast, possibly _also_ send copies out into the mesh.
|
||||
// (FIXME, do something smarter than naive flooding here)
|
||||
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && p->from != getNodeNum()) {
|
||||
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && getFrom(p) != getNodeNum()) {
|
||||
if (p->id != 0) {
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
|
||||
|
||||
|
||||
@@ -101,25 +101,30 @@ template <class T> class MemoryPool : public Allocator<T>
|
||||
/// Return a buffer for use by others
|
||||
virtual void release(T *p)
|
||||
{
|
||||
assert(dead.enqueue(p, 0));
|
||||
assert(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
|
||||
assert(dead.enqueue(p, 0));
|
||||
}
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
/// 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)
|
||||
{
|
||||
assert(dead.enqueueFromISR(p, higherPriWoken));
|
||||
assert(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
|
||||
assert(dead.enqueueFromISR(p, higherPriWoken));
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you
|
||||
/// 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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ static PacketId findId;
|
||||
|
||||
static bool isMyPacket(MeshPacket *p)
|
||||
{
|
||||
return p->id == findId && p->from == findFrom;
|
||||
return p->id == findId && getFrom(p) == findFrom;
|
||||
}
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
#include "MeshPlugin.h"
|
||||
#include "NodeDB.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
#include <assert.h>
|
||||
|
||||
std::vector<MeshPlugin *> *MeshPlugin::plugins;
|
||||
|
||||
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
|
||||
* the RoutingPlugin to avoid sending redundant acks
|
||||
*/
|
||||
MeshPacket *MeshPlugin::currentReply;
|
||||
|
||||
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
|
||||
{
|
||||
// Can't trust static initalizer order, so we check each time
|
||||
if(!plugins)
|
||||
if (!plugins)
|
||||
plugins = new std::vector<MeshPlugin *>();
|
||||
|
||||
plugins->push_back(this);
|
||||
}
|
||||
|
||||
void MeshPlugin::setup() {
|
||||
}
|
||||
void MeshPlugin::setup() {}
|
||||
|
||||
MeshPlugin::~MeshPlugin()
|
||||
{
|
||||
@@ -31,6 +38,8 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
|
||||
assert(mp.which_payloadVariant == MeshPacket_decoded_tag); // I think we are guarnteed the packet is decoded by this point?
|
||||
|
||||
currentReply = NULL; // No reply yet
|
||||
|
||||
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
|
||||
auto ourNodeNum = nodeDB.getNodeNum();
|
||||
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
|
||||
@@ -39,8 +48,15 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
|
||||
pi.currentRequest = ∓
|
||||
|
||||
// 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);
|
||||
/// received channel
|
||||
auto ch = channels.getByIndex(mp.channel);
|
||||
assert(ch.has_settings);
|
||||
|
||||
/// Is the channel this packet arrived on acceptable? (security check)
|
||||
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0);
|
||||
|
||||
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||
bool wantsPacket = rxChannelOk && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||
// DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
if (wantsPacket) {
|
||||
pluginFound = true;
|
||||
@@ -48,15 +64,16 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
bool handled = pi.handleReceived(mp);
|
||||
|
||||
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing)
|
||||
// also: we only let the one plugin send a reply, once that happens, remaining plugins are not 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 && (mp.from != ourNodeNum || mp.to == ourNodeNum)) {
|
||||
// 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 {
|
||||
} else {
|
||||
DEBUG_MSG("Plugin %s considered\n", pi.name);
|
||||
}
|
||||
if (handled) {
|
||||
@@ -64,11 +81,24 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pi.currentRequest = NULL;
|
||||
}
|
||||
|
||||
if(!pluginFound)
|
||||
if (mp.decoded.want_response && toUs) {
|
||||
if (currentReply) {
|
||||
DEBUG_MSG("Sending response\n");
|
||||
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)
|
||||
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum);
|
||||
}
|
||||
|
||||
@@ -76,39 +106,44 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method
|
||||
* is optional
|
||||
*/
|
||||
void MeshPlugin::sendResponse(const MeshPacket &req) {
|
||||
void MeshPlugin::sendResponse(const MeshPacket &req)
|
||||
{
|
||||
auto r = allocReply();
|
||||
if(r) {
|
||||
DEBUG_MSG("Sending response\n");
|
||||
if (r) {
|
||||
setReplyTo(r, req);
|
||||
service.sendToMesh(r);
|
||||
}
|
||||
else {
|
||||
currentReply = r;
|
||||
} else {
|
||||
// Ignore - this is now expected behavior for routing plugin (because it ignores some replies)
|
||||
// DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
void setReplyTo(MeshPacket *p, const MeshPacket &to) {
|
||||
*/
|
||||
void setReplyTo(MeshPacket *p, const MeshPacket &to)
|
||||
{
|
||||
assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now
|
||||
p->to = to.from;
|
||||
p->want_ack = to.want_ack;
|
||||
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)
|
||||
p->want_ack = (to.from != 0) ? to.want_ack : false;
|
||||
if (p->priority == MeshPacket_Priority_UNSET)
|
||||
p->priority = MeshPacket_Priority_RELIABLE;
|
||||
p->decoded.request_id = to.id;
|
||||
}
|
||||
|
||||
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames() {
|
||||
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames()
|
||||
{
|
||||
|
||||
std::vector<MeshPlugin *> pluginsWithUIFrames;
|
||||
std::vector<MeshPlugin *> pluginsWithUIFrames;
|
||||
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
if ( pi.wantUIFrame()) {
|
||||
if (pi.wantUIFrame()) {
|
||||
DEBUG_MSG("Plugin wants a UI Frame\n");
|
||||
pluginsWithUIFrames.push_back(&pi);
|
||||
}
|
||||
}
|
||||
return pluginsWithUIFrames;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "mesh/MeshTypes.h"
|
||||
#include <vector>
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
#include <vector>
|
||||
/** A baseclass for any mesh "plugin".
|
||||
*
|
||||
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
class MeshPlugin
|
||||
{
|
||||
static std::vector<MeshPlugin *> *plugins;
|
||||
static std::vector<MeshPlugin *> *plugins;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
@@ -37,16 +37,24 @@ class MeshPlugin
|
||||
protected:
|
||||
const char *name;
|
||||
|
||||
/* Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific recipient)
|
||||
But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those plugins can set this to
|
||||
true and their handleReceived() will be called for every packet.
|
||||
/* Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
|
||||
recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those
|
||||
plugins can set this to true and their handleReceived() will be called for every packet.
|
||||
*/
|
||||
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
|
||||
* to the packet with the request. This is mostly useful for reply handlers.
|
||||
*
|
||||
*
|
||||
* Note: this can be static because we are guaranteed to be processing only one
|
||||
* plugin at a time.
|
||||
*/
|
||||
@@ -78,9 +86,13 @@ class MeshPlugin
|
||||
*/
|
||||
virtual bool wantUIFrame() { return false; }
|
||||
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
|
||||
* the RoutingPlugin to avoid sending redundant acks
|
||||
*/
|
||||
static MeshPacket *currentReply;
|
||||
friend class ReliableRouter;
|
||||
|
||||
/** 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()
|
||||
@@ -89,7 +101,7 @@ class MeshPlugin
|
||||
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.
|
||||
*/
|
||||
*/
|
||||
void setReplyTo(MeshPacket *p, const MeshPacket &to);
|
||||
@@ -13,8 +13,8 @@
|
||||
#include "RTC.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/PositionPlugin.h"
|
||||
#include "plugins/NodeInfoPlugin.h"
|
||||
#include "plugins/PositionPlugin.h"
|
||||
#include "power.h"
|
||||
|
||||
/*
|
||||
@@ -51,8 +51,6 @@ MeshService service;
|
||||
|
||||
#include "Router.h"
|
||||
|
||||
|
||||
|
||||
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
|
||||
{
|
||||
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
|
||||
@@ -67,7 +65,6 @@ void MeshService::init()
|
||||
gpsObserver.observe(&gps->newStatus);
|
||||
}
|
||||
|
||||
|
||||
int MeshService::handleFromRadio(const MeshPacket *mp)
|
||||
{
|
||||
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
|
||||
@@ -107,7 +104,7 @@ bool MeshService::reloadConfig()
|
||||
// This will also update the region as needed
|
||||
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();
|
||||
|
||||
return didReset;
|
||||
@@ -117,7 +114,8 @@ bool MeshService::reloadConfig()
|
||||
void MeshService::reloadOwner()
|
||||
{
|
||||
assert(nodeInfoPlugin);
|
||||
nodeInfoPlugin->sendOurNodeInfo();
|
||||
if(nodeInfoPlugin)
|
||||
nodeInfoPlugin->sendOurNodeInfo();
|
||||
nodeDB.saveToDisk();
|
||||
}
|
||||
|
||||
@@ -128,8 +126,12 @@ void MeshService::reloadOwner()
|
||||
*/
|
||||
void MeshService::handleToRadio(MeshPacket &p)
|
||||
{
|
||||
if (p.from == 0) // If the phone didn't set a sending node ID, use ours
|
||||
p.from = nodeDB.getNodeNum();
|
||||
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
|
||||
DEBUG_MSG("Warning: phone tried to pick a nodenum, we don't allow that.\n");
|
||||
p.from = 0;
|
||||
} else {
|
||||
// p.from = nodeDB.getNodeNum();
|
||||
}
|
||||
|
||||
if (p.id == 0)
|
||||
p.id = generatePacketId(); // If the phone didn't supply one, then pick one
|
||||
@@ -151,7 +153,8 @@ void MeshService::handleToRadio(MeshPacket &p)
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
|
||||
bool MeshService::cancelSending(PacketId id) {
|
||||
bool MeshService::cancelSending(PacketId id)
|
||||
{
|
||||
return router->cancelSending(nodeDB.getNodeNum(), id);
|
||||
}
|
||||
|
||||
@@ -168,29 +171,36 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
assert(node);
|
||||
|
||||
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
|
||||
assert(positionPlugin && nodeInfoPlugin);
|
||||
if (node->has_position)
|
||||
positionPlugin->sendOurPosition(dest, wantReplies);
|
||||
else
|
||||
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
||||
if (node->has_position) {
|
||||
if(positionPlugin) {
|
||||
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
positionPlugin->sendOurPosition(dest, wantReplies);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(nodeInfoPlugin) {
|
||||
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NodeInfo *MeshService::refreshMyNodeInfo() {
|
||||
NodeInfo *MeshService::refreshMyNodeInfo()
|
||||
{
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
assert(node);
|
||||
|
||||
// We might not have a position yet for our local node, in that case, at least try to send the time
|
||||
if(!node->has_position) {
|
||||
if (!node->has_position) {
|
||||
memset(&node->position, 0, sizeof(node->position));
|
||||
node->has_position = true;
|
||||
}
|
||||
|
||||
|
||||
Position &position = node->position;
|
||||
|
||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||
position.time = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
|
||||
position.time =
|
||||
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
|
||||
|
||||
position.battery_level = powerStatus->getBatteryChargePercent();
|
||||
updateBatteryLevel(position.battery_level);
|
||||
@@ -209,11 +219,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
||||
pos.altitude = gps->altitude;
|
||||
pos.latitude_i = gps->latitude;
|
||||
pos.longitude_i = gps->longitude;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||
// the old position
|
||||
if(radioConfig.preferences.fixed_position) {
|
||||
if (radioConfig.preferences.fixed_position) {
|
||||
DEBUG_MSG("WARNING: Using fixed position\n");
|
||||
} else {
|
||||
// throw away old position
|
||||
|
||||
@@ -32,4 +32,10 @@ typedef uint32_t PacketId; // A packet sequence number
|
||||
typedef int ErrorCode;
|
||||
|
||||
/// Alloc and free packets to our global, ISR safe pool
|
||||
extern Allocator<MeshPacket> &packetPool;
|
||||
extern Allocator<MeshPacket> &packetPool;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* If from is zero this function returns our node number instead
|
||||
*/
|
||||
NodeNum getFrom(const MeshPacket *p);
|
||||
@@ -30,7 +30,8 @@ NodeDB nodeDB;
|
||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||
EXT_RAM_ATTR DeviceState devicestate;
|
||||
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
|
||||
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
||||
@@ -66,6 +67,15 @@ NodeNum displayedNodeNum;
|
||||
|
||||
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. If from is zero this function returns our node number instead
|
||||
*/
|
||||
NodeNum getFrom(const MeshPacket *p)
|
||||
{
|
||||
return (p->from == 0) ? nodeDB.getNodeNum() : p->from;
|
||||
}
|
||||
|
||||
bool NodeDB::resetRadioConfig()
|
||||
{
|
||||
bool didFactoryReset = false;
|
||||
@@ -76,7 +86,7 @@ bool NodeDB::resetRadioConfig()
|
||||
DEBUG_MSG("Performing factory reset!\n");
|
||||
installDefaultDeviceState();
|
||||
didFactoryReset = true;
|
||||
} else if (devicestate.channels_count == 0) {
|
||||
} else if (channelFile.channels_count == 0) {
|
||||
DEBUG_MSG("Setting default channel and radio preferences!\n");
|
||||
|
||||
channels.initDefaults();
|
||||
@@ -109,6 +119,18 @@ bool NodeDB::resetRadioConfig()
|
||||
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()
|
||||
{
|
||||
// We try to preserve the region setting because it will really bum users out if we discard it
|
||||
@@ -121,14 +143,11 @@ void NodeDB::installDefaultDeviceState()
|
||||
|
||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||
devicestate.has_my_node = true;
|
||||
devicestate.has_radio = true;
|
||||
devicestate.has_owner = true;
|
||||
devicestate.radio.has_preferences = true;
|
||||
devicestate.node_db_count = 0;
|
||||
devicestate.version = DEVICESTATE_CUR_VER;
|
||||
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
||||
|
||||
resetRadioConfig();
|
||||
|
||||
// default to no GPS, until one has been found by probing
|
||||
myNodeInfo.has_gps = false;
|
||||
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
|
||||
@@ -150,6 +169,9 @@ void NodeDB::installDefaultDeviceState()
|
||||
radioConfig.preferences.region = oldRegionCode;
|
||||
if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date
|
||||
strcpy(myNodeInfo.region, oldRegion.c_str());
|
||||
|
||||
installDefaultChannels();
|
||||
installDefaultRadioConfig();
|
||||
}
|
||||
|
||||
void NodeDB::init()
|
||||
@@ -173,17 +195,24 @@ void NodeDB::init()
|
||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||
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
|
||||
NodeInfo *info = getOrCreateNode(getNodeNum());
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
// removed from 1.2 (though we do use old values if found)
|
||||
// We set these _after_ loading from disk - because they come from the build and are more trusted than
|
||||
// what is stored in flash
|
||||
if (xstr(HW_VERSION)[0])
|
||||
strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
|
||||
else
|
||||
DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build flag
|
||||
//if (xstr(HW_VERSION)[0])
|
||||
// strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
|
||||
// else DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build flag
|
||||
|
||||
// DEBUG_MSG("legacy region %d\n", devicestate.legacyRadio.preferences.region);
|
||||
if(radioConfig.preferences.region == RegionCode_Unset)
|
||||
radioConfig.preferences.region = devicestate.legacyRadio.preferences.region;
|
||||
|
||||
// Check for the old style of region code strings, if found, convert to the new enum.
|
||||
// Those strings will look like "1.0-EU433"
|
||||
@@ -197,12 +226,14 @@ void NodeDB::init()
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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,
|
||||
myNodeInfo.my_node_num, *numNodes);
|
||||
DEBUG_MSG("region=%d, NODENUM=0x%x, dbsize=%d\n", radioConfig.preferences.region, myNodeInfo.my_node_num, *numNodes);
|
||||
}
|
||||
|
||||
// We reserve a few nodenums for future use
|
||||
@@ -232,84 +263,134 @@ void NodeDB::pickNewNodeNum()
|
||||
myNodeInfo.my_node_num = r;
|
||||
}
|
||||
|
||||
const char *preffile = "/db.proto";
|
||||
const char *preftmp = "/db.proto.tmp";
|
||||
static const char *preffileOld = "/db.proto";
|
||||
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
|
||||
// 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) {
|
||||
DEBUG_MSG("Loading saved preferences\n");
|
||||
pb_istream_t stream = {&readcb, &f, DeviceState_size};
|
||||
DEBUG_MSG("Loading %s\n", filename);
|
||||
pb_istream_t stream = {&readcb, &f, protoSize};
|
||||
|
||||
// DEBUG_MSG("Preload channel name=%s\n", channelSettings.name);
|
||||
|
||||
memset(&devicestate, 0, sizeof(devicestate));
|
||||
if (!pb_decode(&stream, DeviceState_fields, &devicestate)) {
|
||||
memset(dest_struct, 0, objSize);
|
||||
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||
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 {
|
||||
if (devicestate.version < DEVICESTATE_MIN_VER) {
|
||||
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);
|
||||
okay = true;
|
||||
}
|
||||
|
||||
f.close();
|
||||
} else {
|
||||
DEBUG_MSG("No saved preferences found\n");
|
||||
DEBUG_MSG("No %s preferences found\n", filename);
|
||||
}
|
||||
|
||||
#else
|
||||
DEBUG_MSG("ERROR: Filesystem not implemented\n");
|
||||
#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()
|
||||
{
|
||||
#ifdef FS
|
||||
if (!devicestate.no_save) {
|
||||
auto f = FS.open(preftmp, FILE_O_WRITE);
|
||||
if (f) {
|
||||
DEBUG_MSG("Writing preferences\n");
|
||||
#ifdef FS
|
||||
FS.mkdir("/prefs");
|
||||
#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};
|
||||
|
||||
// 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
|
||||
}
|
||||
// remove any pre 1.2 pref files, turn on after 1.2 is in beta
|
||||
// if(okay) FS.remove(preffileOld);
|
||||
} else {
|
||||
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()
|
||||
@@ -362,7 +443,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
|
||||
// recorded based on the packet rxTime
|
||||
if (!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;
|
||||
if (p.latitude_i || p.longitude_i) {
|
||||
info->position.latitude_i = p.latitude_i;
|
||||
@@ -406,7 +487,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
if (mp.which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||
|
||||
NodeInfo *info = getOrCreateNode(mp.from);
|
||||
NodeInfo *info = getOrCreateNode(getFrom(&mp));
|
||||
|
||||
if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
|
||||
info->has_position = true; // at least the time is valid
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
extern DeviceState devicestate;
|
||||
extern ChannelFile channelFile;
|
||||
extern MyNodeInfo &myNodeInfo;
|
||||
extern RadioConfig &radioConfig;
|
||||
extern RadioConfig radioConfig;
|
||||
extern User &owner;
|
||||
|
||||
/// 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();
|
||||
|
||||
/// write to flash
|
||||
void saveToDisk();
|
||||
void saveToDisk(), saveChannelsToDisk();
|
||||
|
||||
/** Reinit radio config if needed, because either:
|
||||
* a) sometimes a buggy android app might send us bogus settings or
|
||||
@@ -117,7 +118,7 @@ class NodeDB
|
||||
void loadFromDisk();
|
||||
|
||||
/// Reinit device state from scratch (not loading from disk)
|
||||
void installDefaultDeviceState();
|
||||
void installDefaultDeviceState(), installDefaultRadioConfig(), installDefaultChannels();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -183,3 +184,4 @@ PREF_GET(min_wake_secs, 10)
|
||||
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
||||
*/
|
||||
extern uint32_t radioGeneration;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
||||
// DEBUG_MSG("Deleting old broadcast record %d\n", i);
|
||||
recentPackets.erase(recentPackets.begin() + i); // delete old record
|
||||
} else {
|
||||
if (r.id == p->id && r.sender == p->from) {
|
||||
if (r.id == p->id && r.sender == getFrom(p)) {
|
||||
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
|
||||
// Update the time on this record to now
|
||||
@@ -43,7 +43,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
||||
if (withUpdate) {
|
||||
PacketRecord r;
|
||||
r.id = p->id;
|
||||
r.sender = p->from;
|
||||
r.sender = getFrom(p);
|
||||
r.rxTimeMsec = now;
|
||||
recentPackets.push_back(r);
|
||||
printPacket("Adding packet record", p);
|
||||
|
||||
@@ -59,6 +59,7 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
}
|
||||
// return (lastContactMsec != 0) &&
|
||||
|
||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
||||
switch (toRadioScratch.which_payloadVariant) {
|
||||
case ToRadio_packet_tag: {
|
||||
@@ -155,7 +156,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
state = STATE_SEND_PACKETS;
|
||||
break;
|
||||
|
||||
case STATE_LEGACY: // Treat as the same as send packets
|
||||
case STATE_SEND_PACKETS:
|
||||
// Do we have a message from the mesh?
|
||||
if (packetForPhone) {
|
||||
@@ -178,9 +178,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
// Do we have a message from the mesh?
|
||||
if (fromRadioScratch.which_payloadVariant != 0) {
|
||||
// Encapsulate as a FromRadio packet
|
||||
DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_payloadVariant);
|
||||
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
|
||||
DEBUG_MSG(", %d bytes\n", numbytes);
|
||||
// DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payloadVariant, numbytes);
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
@@ -208,7 +207,6 @@ bool PhoneAPI::available()
|
||||
case STATE_SEND_COMPLETE_ID:
|
||||
return true;
|
||||
|
||||
case STATE_LEGACY: // Treat as the same as send packets
|
||||
case STATE_SEND_PACKETS: {
|
||||
// Try to pull a new packet from the service (if we haven't already)
|
||||
if (!packetForPhone)
|
||||
@@ -236,7 +234,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
|
||||
// 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);
|
||||
onNowHasData(newValue);
|
||||
} else
|
||||
|
||||
@@ -20,7 +20,7 @@ class PhoneAPI
|
||||
: public Observer<uint32_t> // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
|
||||
{
|
||||
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_MY_INFO, // send our my info record
|
||||
// STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet
|
||||
|
||||
@@ -58,11 +58,12 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
|
||||
// it would be better to update even if the message was destined to others.
|
||||
|
||||
auto &p = mp.decoded;
|
||||
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size);
|
||||
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, portnum=%d, payloadlen=%d\n", name, mp.from, mp.id, p.portnum, p.payload.size);
|
||||
|
||||
T scratch;
|
||||
T *decoded = NULL;
|
||||
if(mp.decoded.portnum == ourPortNum) {
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
|
||||
decoded = &scratch;
|
||||
else
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "assert.h"
|
||||
#include "configuration.h"
|
||||
#include "Router.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
#include "Channels.h"
|
||||
|
||||
#define RDEF(name, freq, spacing, num_ch, power_limit) \
|
||||
{ \
|
||||
@@ -25,9 +25,27 @@ const RegionInfo regions[] = {
|
||||
RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel
|
||||
// freq. (921.9f is for download, others are for uplink)
|
||||
RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz)
|
||||
RDEF(RU, 868.9f, 0.2f, 2, 20), // See notes below
|
||||
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
|
||||
};
|
||||
|
||||
/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2):
|
||||
|
||||
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018) https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1
|
||||
We have 3 options for 868 MHz:
|
||||
|
||||
864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports.
|
||||
866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports
|
||||
868,7 - 869,2 MHz ERP 100mW, Duty Cycle 10% or LBT, no resctrictions
|
||||
and according to RP2-1.0.2 LoRaWAN® Regional Parameters RP2-1.0.2 LoRaWAN® Regional Parameters - LoRa Alliance®
|
||||
I propose to use following meshtastic bandplan:
|
||||
1 channel - central frequency 868.9MHz 125kHz band
|
||||
Protective band - 75kHz
|
||||
2 channel - central frequency 869.1MHz 125kHz band
|
||||
|
||||
RDEF(RU, 868.9f, 0.2f, 2, 20)
|
||||
*/
|
||||
|
||||
const RegionInfo *myRegion;
|
||||
|
||||
void initRegion()
|
||||
@@ -119,11 +137,11 @@ uint32_t RadioInterface::getTxDelayMsec()
|
||||
|
||||
void printPacket(const char *prefix, const MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
|
||||
p->hop_limit, p->channel);
|
||||
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
p->want_ack, p->hop_limit, p->channel);
|
||||
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
auto &s = p->decoded;
|
||||
|
||||
|
||||
DEBUG_MSG(" Portnum=%d", s.portnum);
|
||||
|
||||
if (s.want_response)
|
||||
@@ -135,6 +153,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
if (s.dest != 0)
|
||||
DEBUG_MSG(" dest=%08x", s.dest);
|
||||
|
||||
if(s.request_id)
|
||||
DEBUG_MSG(" requestId=%0x", s.request_id);
|
||||
|
||||
/* now inside Data and therefore kinda opaque
|
||||
if (s.which_ackVariant == SubPacket_success_id_tag)
|
||||
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
|
||||
@@ -332,6 +353,10 @@ void RadioInterface::deliverToReceiver(MeshPacket *p)
|
||||
{
|
||||
assert(rxDest);
|
||||
assert(rxDest->enqueue(p, 0)); // NOWAIT - fixme, if queue is full, delete older messages
|
||||
|
||||
// Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME
|
||||
if (router)
|
||||
router->setReceivedMessage();
|
||||
}
|
||||
|
||||
/***
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ReliableRouter.h"
|
||||
#include "MeshPlugin.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
@@ -13,9 +14,10 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
|
||||
{
|
||||
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
|
||||
// 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)
|
||||
p->hop_limit = 1;
|
||||
p->hop_limit = HOP_RELIABLE;
|
||||
|
||||
auto copy = packetPool.allocCopy(*p);
|
||||
startRetransmission(copy);
|
||||
@@ -26,15 +28,26 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
|
||||
|
||||
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
{
|
||||
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
|
||||
if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) {
|
||||
printPacket("Rx someone rebroadcasting for us", p);
|
||||
|
||||
// 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
|
||||
// the original sending process.
|
||||
if (stopRetransmission(p->from, p->id)) {
|
||||
DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n");
|
||||
sendAckNak(Routing_Error_NONE, p->from, 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");
|
||||
// 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
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
|
||||
|
||||
stopRetransmission(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,23 +73,26 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability
|
||||
// - not DSR routing)
|
||||
if (p->want_ack) {
|
||||
sendAckNak(Routing_Error_NONE, p->from, p->id);
|
||||
if (MeshPlugin::currentReply)
|
||||
DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack\n");
|
||||
else
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
}
|
||||
|
||||
// If the payload is valid, look for ack/nak
|
||||
if (c) {
|
||||
PacketId ackId = c->error_reason == Routing_Error_NONE ? p->decoded.request_id : 0;
|
||||
PacketId nakId = c->error_reason != Routing_Error_NONE ? p->decoded.request_id : 0;
|
||||
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
|
||||
PacketId ackId = ((c && c->error_reason == Routing_Error_NONE) || !c) ? p->decoded.request_id : 0;
|
||||
|
||||
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
||||
if (ackId || nakId) {
|
||||
if (ackId) {
|
||||
DEBUG_MSG("Received a ack=%d, stopping retransmissions\n", ackId);
|
||||
stopRetransmission(p->to, ackId);
|
||||
} else {
|
||||
DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId);
|
||||
stopRetransmission(p->to, nakId);
|
||||
}
|
||||
// A nak is a routing packt that has an error code
|
||||
PacketId nakId = (c && c->error_reason != Routing_Error_NONE) ? p->decoded.request_id : 0;
|
||||
|
||||
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
||||
if (ackId || nakId) {
|
||||
if (ackId) {
|
||||
DEBUG_MSG("Received a ack for 0x%x, stopping retransmissions\n", ackId);
|
||||
stopRetransmission(p->to, ackId);
|
||||
} else {
|
||||
DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId);
|
||||
stopRetransmission(p->to, nakId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,8 +146,9 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
|
||||
auto id = GlobalPacketId(p);
|
||||
auto rec = PendingPacket(p);
|
||||
|
||||
stopRetransmission(getFrom(p), p->id);
|
||||
|
||||
setNextTx(&rec);
|
||||
stopRetransmission(p->from, p->id);
|
||||
pending[id] = rec;
|
||||
|
||||
return &pending[id];
|
||||
@@ -151,18 +168,21 @@ int32_t ReliableRouter::doRetransmissions()
|
||||
++nextIt; // we use this odd pattern because we might be deleting it...
|
||||
auto &p = it->second;
|
||||
|
||||
bool stillValid = true; // assume we'll keep this record around
|
||||
|
||||
// FIXME, handle 51 day rolloever here!!!
|
||||
if (p.nextTxMsec <= now) {
|
||||
if (p.numRetransmissions == 0) {
|
||||
DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\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);
|
||||
sendAckNak(Routing_Error_MAX_RETRANSMIT, p.packet->from, 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
|
||||
// allows the DSR version to still be able to look at the PendingPacket
|
||||
stopRetransmission(it->first);
|
||||
stillValid = false; // just deleted it
|
||||
} else {
|
||||
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=%d, tries left=%d\n", p.packet->from, p.packet->to,
|
||||
p.packet->id, p.numRetransmissions);
|
||||
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
|
||||
p.packet->to, p.packet->id, p.numRetransmissions);
|
||||
|
||||
// Note: we call the superclass version because we don't want to have our version of send() add a new
|
||||
// retransmission record
|
||||
@@ -172,8 +192,10 @@ int32_t ReliableRouter::doRetransmissions()
|
||||
--p.numRetransmissions;
|
||||
setNextTx(&p);
|
||||
}
|
||||
} else {
|
||||
// Not yet time
|
||||
}
|
||||
|
||||
if (stillValid) {
|
||||
// Update our desired sleep delay
|
||||
int32_t t = p.nextTxMsec - now;
|
||||
|
||||
d = min(t, d);
|
||||
@@ -181,4 +203,14 @@ int32_t ReliableRouter::doRetransmissions()
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void ReliableRouter::setNextTx(PendingPacket *pending)
|
||||
{
|
||||
assert(iface);
|
||||
auto d = iface->getRetransmissionMsec(pending->packet);
|
||||
pending->nextTxMsec = millis() + d;
|
||||
DEBUG_MSG("Setting next retransmission in %u msecs: ", d);
|
||||
printPacket("", pending->packet);
|
||||
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
|
||||
}
|
||||
@@ -15,7 +15,7 @@ struct GlobalPacketId {
|
||||
|
||||
GlobalPacketId(const MeshPacket *p)
|
||||
{
|
||||
node = p->from;
|
||||
node = getFrom(p);
|
||||
id = p->id;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,5 @@ class ReliableRouter : public FloodingRouter
|
||||
*/
|
||||
int32_t doRetransmissions();
|
||||
|
||||
void setNextTx(PendingPacket *pending) {
|
||||
assert(iface);
|
||||
pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); }
|
||||
void setNextTx(PendingPacket *pending);
|
||||
};
|
||||
|
||||
@@ -103,24 +103,29 @@ MeshPacket *Router::allocForSending()
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err);
|
||||
sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id);
|
||||
sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id, p->channel);
|
||||
packetPool.release(p);
|
||||
}
|
||||
|
||||
void Router::setReceivedMessage() {
|
||||
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
{
|
||||
// No need to deliver externally if the destination is the local node
|
||||
if (p->to == nodeDB.getNodeNum()) {
|
||||
printPacket("Enqueuing local", p);
|
||||
fromRadioQueue.enqueue(p);
|
||||
setReceivedMessage();
|
||||
return ERRNO_OK;
|
||||
} else if (!iface) {
|
||||
// We must be sending to remote nodes also, fail if no interface found
|
||||
@@ -138,6 +143,13 @@ ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
}
|
||||
}
|
||||
|
||||
void printBytes(const char *label, const uint8_t *p, size_t numbytes) {
|
||||
DEBUG_MSG("%s: ", label);
|
||||
for(size_t i = 0; i < numbytes; i++)
|
||||
DEBUG_MSG("%02x ", p[i]);
|
||||
DEBUG_MSG("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet on a suitable interface. This routine will
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
@@ -155,6 +167,10 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
if (p->to == NODENUM_BROADCAST)
|
||||
p->want_ack = false;
|
||||
|
||||
// Up until this point we might have been using 0 for the from address (if it started with the phone), but when we send over
|
||||
// the lora we need to make sure we have replaced it with our local address
|
||||
p->from = getFrom(p);
|
||||
|
||||
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
|
||||
|
||||
assert(p->which_payloadVariant == MeshPacket_encrypted_tag ||
|
||||
@@ -164,6 +180,8 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
|
||||
|
||||
// printPacket("pre encrypt", p); // portnum valid here
|
||||
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
|
||||
if (numbytes > MAX_RHPACKETLEN) {
|
||||
@@ -171,6 +189,8 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
return ERRNO_TOO_LARGE;
|
||||
}
|
||||
|
||||
//printBytes("plaintext", bytes, numbytes);
|
||||
|
||||
auto hash = channels.setActiveByIndex(p->channel);
|
||||
if (hash < 0) {
|
||||
// No suitable channel could be found for sending
|
||||
@@ -180,7 +200,7 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
|
||||
// Now that we are encrypting the packet channel should be the hash (no longer the index)
|
||||
p->channel = hash;
|
||||
crypto->encrypt(p->from, p->id, numbytes, bytes);
|
||||
crypto->encrypt(getFrom(p), p->id, numbytes, bytes);
|
||||
|
||||
// Copy back into the packet and set the variant type
|
||||
memcpy(p->encrypted.bytes, bytes, numbytes);
|
||||
@@ -221,19 +241,26 @@ bool Router::perhapsDecode(MeshPacket *p)
|
||||
if (channels.decryptForHash(chIndex, p->channel)) {
|
||||
// Try to decrypt the packet if we can
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
size_t rawSize = p->encrypted.size;
|
||||
assert(rawSize <= sizeof(bytes));
|
||||
memcpy(bytes, p->encrypted.bytes,
|
||||
p->encrypted
|
||||
.size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
|
||||
crypto->decrypt(p->from, p->id, p->encrypted.size, bytes);
|
||||
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);
|
||||
|
||||
//printBytes("plaintext", bytes, p->encrypted.size);
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) {
|
||||
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n");
|
||||
} else {
|
||||
memset(&p->decoded, 0, sizeof(p->decoded));
|
||||
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
|
||||
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
|
||||
} else if(p->decoded.portnum == PortNum_UNKNOWN_APP) {
|
||||
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
|
||||
}
|
||||
else {
|
||||
// parsing was successful
|
||||
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
|
||||
p->channel = chIndex; // change to store the index instead of the hash
|
||||
// printPacket("decoded message", p);
|
||||
p->which_payloadVariant = MeshPacket_decoded_tag;
|
||||
printPacket("decoded message", p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -258,11 +285,10 @@ void Router::handleReceived(MeshPacket *p)
|
||||
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
|
||||
bool decoded = perhapsDecode(p);
|
||||
printPacket("handleReceived", p);
|
||||
DEBUG_MSG("decoded=%d\n", decoded);
|
||||
bool decoded = perhapsDecode(p);
|
||||
if (decoded) {
|
||||
// parsing was successful, queue for our recipient
|
||||
printPacket("handleReceived", p);
|
||||
|
||||
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
|
||||
// sniffReceived(p);
|
||||
@@ -273,7 +299,7 @@ void Router::handleReceived(MeshPacket *p)
|
||||
void Router::perhapsHandleReceived(MeshPacket *p)
|
||||
{
|
||||
assert(radioConfig.has_preferences);
|
||||
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, p->from);
|
||||
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, getFrom(p));
|
||||
|
||||
if (ignore)
|
||||
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "PointerQueue.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "Channels.h"
|
||||
|
||||
/**
|
||||
* A mesh aware router that supports multiple interfaces.
|
||||
@@ -63,6 +64,11 @@ class Router : protected concurrency::OSThread
|
||||
* @return our local nodenum */
|
||||
NodeNum getNodeNum();
|
||||
|
||||
/** Wake up the router thread ASAP, because we just queued a message for it.
|
||||
* FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue'
|
||||
*/
|
||||
void setReceivedMessage();
|
||||
|
||||
protected:
|
||||
friend class RoutingPlugin;
|
||||
|
||||
@@ -101,7 +107,7 @@ class Router : protected concurrency::OSThread
|
||||
/**
|
||||
* 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:
|
||||
/**
|
||||
|
||||
@@ -71,12 +71,18 @@ void StreamAPI::writeStream()
|
||||
void StreamAPI::emitTxBuffer(size_t len)
|
||||
{
|
||||
if (len != 0) {
|
||||
DEBUG_MSG("emit tx %d\n", len);
|
||||
txBuf[0] = START1;
|
||||
txBuf[1] = START2;
|
||||
txBuf[2] = (len >> 8) & 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();
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ typedef struct _AdminMessage {
|
||||
RadioConfig get_radio_response;
|
||||
uint32_t get_channel_request;
|
||||
Channel get_channel_response;
|
||||
bool confirm_set_channel;
|
||||
bool confirm_set_radio;
|
||||
bool exit_simulator;
|
||||
};
|
||||
} AdminMessage;
|
||||
|
||||
@@ -43,6 +46,9 @@ extern "C" {
|
||||
#define AdminMessage_get_radio_response_tag 5
|
||||
#define AdminMessage_get_channel_request_tag 6
|
||||
#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
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define AdminMessage_FIELDLIST(X, a) \
|
||||
@@ -52,7 +58,10 @@ 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, 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, 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)
|
||||
#define AdminMessage_CALLBACK NULL
|
||||
#define AdminMessage_DEFAULT NULL
|
||||
#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig
|
||||
@@ -67,7 +76,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
|
||||
#define AdminMessage_fields &AdminMessage_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define AdminMessage_size 338
|
||||
#define AdminMessage_size 351
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -40,7 +40,7 @@ typedef struct _ChannelSettings {
|
||||
} ChannelSettings;
|
||||
|
||||
typedef struct _Channel {
|
||||
uint8_t index;
|
||||
int8_t index;
|
||||
bool has_settings;
|
||||
ChannelSettings settings;
|
||||
Channel_Role role;
|
||||
@@ -100,7 +100,7 @@ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17)
|
||||
#define ChannelSettings_DEFAULT NULL
|
||||
|
||||
#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, SINGULAR, UENUM, role, 3)
|
||||
#define Channel_CALLBACK NULL
|
||||
@@ -116,7 +116,7 @@ extern const pb_msgdesc_t Channel_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ChannelSettings_size 87
|
||||
#define Channel_size 94
|
||||
#define Channel_size 102
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -6,7 +6,16 @@
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(LegacyRadioConfig, LegacyRadioConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(LegacyRadioConfig_LegacyPreferences, LegacyRadioConfig_LegacyPreferences, AUTO)
|
||||
|
||||
|
||||
PB_BIND(DeviceState, DeviceState, 2)
|
||||
|
||||
|
||||
PB_BIND(ChannelFile, ChannelFile, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,17 +5,31 @@
|
||||
#define PB_DEVICEONLY_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
#include "mesh.pb.h"
|
||||
#include "radioconfig.pb.h"
|
||||
#include "channel.pb.h"
|
||||
#include "radioconfig.pb.h"
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
/* 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 {
|
||||
bool has_radio;
|
||||
RadioConfig radio;
|
||||
bool has_legacyRadio;
|
||||
LegacyRadioConfig legacyRadio;
|
||||
bool has_my_node;
|
||||
MyNodeInfo my_node;
|
||||
bool has_owner;
|
||||
@@ -29,8 +43,6 @@ typedef struct _DeviceState {
|
||||
uint32_t version;
|
||||
bool no_save;
|
||||
bool did_gps_reset;
|
||||
pb_size_t channels_count;
|
||||
Channel channels[8];
|
||||
} DeviceState;
|
||||
|
||||
|
||||
@@ -39,11 +51,20 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* 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 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_init_default {false, LegacyRadioConfig_LegacyPreferences_init_default}
|
||||
#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) */
|
||||
#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_owner_tag 3
|
||||
#define DeviceState_node_db_tag 4
|
||||
@@ -52,11 +73,21 @@ extern "C" {
|
||||
#define DeviceState_version_tag 8
|
||||
#define DeviceState_no_save_tag 9
|
||||
#define DeviceState_did_gps_reset_tag 11
|
||||
#define DeviceState_channels_tag 13
|
||||
|
||||
/* 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) \
|
||||
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, owner, 3) \
|
||||
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, SINGULAR, UINT32, version, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, channels, 13)
|
||||
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11)
|
||||
#define DeviceState_CALLBACK NULL
|
||||
#define DeviceState_DEFAULT NULL
|
||||
#define DeviceState_radio_MSGTYPE RadioConfig
|
||||
#define DeviceState_legacyRadio_MSGTYPE LegacyRadioConfig
|
||||
#define DeviceState_my_node_MSGTYPE MyNodeInfo
|
||||
#define DeviceState_owner_MSGTYPE User
|
||||
#define DeviceState_node_db_MSGTYPE NodeInfo
|
||||
#define DeviceState_receive_queue_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 ChannelFile_msg;
|
||||
|
||||
/* 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 ChannelFile_fields &ChannelFile_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define DeviceState_size 6156
|
||||
#define LegacyRadioConfig_size 4
|
||||
#define LegacyRadioConfig_LegacyPreferences_size 2
|
||||
#define DeviceState_size 4898
|
||||
#define ChannelFile_size 832
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -45,3 +45,4 @@ PB_BIND(ToRadio, ToRadio, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,25 @@
|
||||
#endif
|
||||
|
||||
/* 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 {
|
||||
Constants_Unused = 0,
|
||||
Constants_DATA_PAYLOAD_LEN = 240
|
||||
@@ -25,7 +44,8 @@ typedef enum _CriticalErrorCode {
|
||||
CriticalErrorCode_UBloxInitFailed = 5,
|
||||
CriticalErrorCode_NoAXP192 = 6,
|
||||
CriticalErrorCode_InvalidRadioSetting = 7,
|
||||
CriticalErrorCode_TransmitFailed = 8
|
||||
CriticalErrorCode_TransmitFailed = 8,
|
||||
CriticalErrorCode_Brownout = 9
|
||||
} CriticalErrorCode;
|
||||
|
||||
typedef enum _Routing_Error {
|
||||
@@ -36,7 +56,8 @@ typedef enum _Routing_Error {
|
||||
Routing_Error_NO_INTERFACE = 4,
|
||||
Routing_Error_MAX_RETRANSMIT = 5,
|
||||
Routing_Error_NO_CHANNEL = 6,
|
||||
Routing_Error_TOO_LARGE = 7
|
||||
Routing_Error_TOO_LARGE = 7,
|
||||
Routing_Error_NO_RESPONSE = 8
|
||||
} Routing_Error;
|
||||
|
||||
typedef enum _MeshPacket_Priority {
|
||||
@@ -82,7 +103,7 @@ typedef struct _MyNodeInfo {
|
||||
bool has_gps;
|
||||
uint32_t num_bands;
|
||||
char region[12];
|
||||
char hw_model[16];
|
||||
char hw_model_deprecated[16];
|
||||
char firmware_version[12];
|
||||
CriticalErrorCode error_code;
|
||||
uint32_t error_address;
|
||||
@@ -110,6 +131,7 @@ typedef struct _User {
|
||||
char long_name[40];
|
||||
char short_name[5];
|
||||
pb_byte_t macaddr[6];
|
||||
HardwareModel hw_model;
|
||||
} User;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
|
||||
@@ -136,7 +158,6 @@ typedef struct _NodeInfo {
|
||||
User user;
|
||||
bool has_position;
|
||||
Position position;
|
||||
uint32_t next_hop;
|
||||
float snr;
|
||||
} NodeInfo;
|
||||
|
||||
@@ -172,17 +193,21 @@ typedef struct _ToRadio {
|
||||
|
||||
|
||||
/* 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_MAX Constants_DATA_PAYLOAD_LEN
|
||||
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
|
||||
|
||||
#define _CriticalErrorCode_MIN CriticalErrorCode_None
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1))
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_Brownout
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_Brownout+1))
|
||||
|
||||
#define _Routing_Error_MIN Routing_Error_NONE
|
||||
#define _Routing_Error_MAX Routing_Error_TOO_LARGE
|
||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_TOO_LARGE+1))
|
||||
#define _Routing_Error_MAX Routing_Error_NO_RESPONSE
|
||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_NO_RESPONSE+1))
|
||||
|
||||
#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET
|
||||
#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX
|
||||
@@ -199,23 +224,23 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#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 Routing_init_default {0, {RouteDiscovery_init_default}}
|
||||
#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 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}
|
||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
|
||||
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
||||
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
|
||||
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
||||
#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 Routing_init_zero {0, {RouteDiscovery_init_zero}}
|
||||
#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 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}
|
||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
|
||||
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
|
||||
@@ -236,7 +261,7 @@ extern "C" {
|
||||
#define MyNodeInfo_has_gps_tag 2
|
||||
#define MyNodeInfo_num_bands_tag 3
|
||||
#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_error_code_tag 7
|
||||
#define MyNodeInfo_error_address_tag 8
|
||||
@@ -254,6 +279,7 @@ extern "C" {
|
||||
#define User_long_name_tag 2
|
||||
#define User_short_name_tag 3
|
||||
#define User_macaddr_tag 4
|
||||
#define User_hw_model_tag 6
|
||||
#define MeshPacket_from_tag 1
|
||||
#define MeshPacket_to_tag 2
|
||||
#define MeshPacket_channel_tag 3
|
||||
@@ -268,7 +294,6 @@ extern "C" {
|
||||
#define NodeInfo_num_tag 1
|
||||
#define NodeInfo_user_tag 2
|
||||
#define NodeInfo_position_tag 3
|
||||
#define NodeInfo_next_hop_tag 5
|
||||
#define NodeInfo_snr_tag 7
|
||||
#define Routing_route_request_tag 1
|
||||
#define Routing_route_reply_tag 2
|
||||
@@ -297,7 +322,8 @@ X(a, STATIC, SINGULAR, FIXED32, time, 9)
|
||||
X(a, STATIC, SINGULAR, STRING, id, 1) \
|
||||
X(a, STATIC, SINGULAR, STRING, long_name, 2) \
|
||||
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_DEFAULT NULL
|
||||
|
||||
@@ -345,7 +371,6 @@ X(a, STATIC, SINGULAR, UENUM, priority, 12)
|
||||
X(a, STATIC, SINGULAR, UINT32, num, 1) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, next_hop, 5) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 7)
|
||||
#define NodeInfo_CALLBACK NULL
|
||||
#define NodeInfo_DEFAULT NULL
|
||||
@@ -357,7 +382,7 @@ X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, num_bands, 3) \
|
||||
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, UENUM, error_code, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error_address, 8) \
|
||||
@@ -425,12 +450,12 @@ extern const pb_msgdesc_t ToRadio_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define Position_size 37
|
||||
#define User_size 72
|
||||
#define User_size 74
|
||||
#define RouteDiscovery_size 40
|
||||
#define Routing_size 42
|
||||
#define Data_size 260
|
||||
#define MeshPacket_size 298
|
||||
#define NodeInfo_size 130
|
||||
#define NodeInfo_size 126
|
||||
#define MyNodeInfo_size 89
|
||||
#define LogRecord_size 81
|
||||
#define FromRadio_size 307
|
||||
|
||||
@@ -20,10 +20,10 @@ typedef enum _PortNum {
|
||||
PortNum_ADMIN_APP = 6,
|
||||
PortNum_REPLY_APP = 32,
|
||||
PortNum_IP_TUNNEL_APP = 33,
|
||||
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 34,
|
||||
PortNum_SERIAL_APP = 64,
|
||||
PortNum_STORE_FORWARD_APP = 65,
|
||||
PortNum_RANGE_TEST_APP = 66,
|
||||
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67,
|
||||
PortNum_PRIVATE_APP = 256,
|
||||
PortNum_ATAK_FORWARDER = 257,
|
||||
PortNum_MAX = 511
|
||||
|
||||
@@ -17,3 +17,4 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ typedef enum _RegionCode {
|
||||
RegionCode_JP = 5,
|
||||
RegionCode_ANZ = 6,
|
||||
RegionCode_KR = 7,
|
||||
RegionCode_TW = 8
|
||||
RegionCode_TW = 8,
|
||||
RegionCode_RU = 9
|
||||
} RegionCode;
|
||||
|
||||
typedef enum _ChargeCurrent {
|
||||
@@ -56,6 +57,10 @@ typedef enum _LocationSharing {
|
||||
LocationSharing_LocDisabled = 2
|
||||
} LocationSharing;
|
||||
|
||||
typedef enum _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType {
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 = 0
|
||||
} RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _RadioConfig_UserPreferences {
|
||||
uint32_t position_broadcast_secs;
|
||||
@@ -99,13 +104,16 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
bool range_test_plugin_enabled;
|
||||
uint32_t range_test_plugin_sender;
|
||||
bool range_test_plugin_save;
|
||||
bool store_forward_plugin_enabled;
|
||||
uint32_t store_forward_plugin_records;
|
||||
bool environmental_measurement_plugin_measurement_enabled;
|
||||
bool environmental_measurement_plugin_screen_enabled;
|
||||
uint32_t environmental_measurement_plugin_read_error_count_threshold;
|
||||
uint32_t environmental_measurement_plugin_update_interval;
|
||||
uint32_t environmental_measurement_plugin_recovery_interval;
|
||||
bool environmental_measurement_plugin_display_farenheit;
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type;
|
||||
uint32_t environmental_measurement_plugin_sensor_pin;
|
||||
bool store_forward_plugin_enabled;
|
||||
} RadioConfig_UserPreferences;
|
||||
|
||||
typedef struct _RadioConfig {
|
||||
@@ -116,8 +124,8 @@ typedef struct _RadioConfig {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _RegionCode_MIN RegionCode_Unset
|
||||
#define _RegionCode_MAX RegionCode_TW
|
||||
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
|
||||
#define _RegionCode_MAX RegionCode_RU
|
||||
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_RU+1))
|
||||
|
||||
#define _ChargeCurrent_MIN ChargeCurrent_MAUnset
|
||||
#define _ChargeCurrent_MAX ChargeCurrent_MA1320
|
||||
@@ -131,6 +139,10 @@ typedef struct _RadioConfig {
|
||||
#define _LocationSharing_MAX LocationSharing_LocDisabled
|
||||
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
|
||||
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11+1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -138,9 +150,9 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#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}
|
||||
#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, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
|
||||
#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}
|
||||
#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, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
||||
@@ -183,13 +195,16 @@ extern "C" {
|
||||
#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132
|
||||
#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133
|
||||
#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_environmental_measurement_plugin_measurement_enabled_tag 140
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144
|
||||
#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_pin_tag 147
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 148
|
||||
#define RadioConfig_preferences_tag 1
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
@@ -240,13 +255,16 @@ 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, UINT32, range_test_plugin_sender, 133) \
|
||||
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, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \
|
||||
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
|
||||
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \
|
||||
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \
|
||||
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, UENUM, environmental_measurement_plugin_sensor_type, 146) \
|
||||
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_DEFAULT NULL
|
||||
|
||||
@@ -258,8 +276,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
|
||||
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define RadioConfig_size 335
|
||||
#define RadioConfig_UserPreferences_size 332
|
||||
#define RadioConfig_size 348
|
||||
#define RadioConfig_UserPreferences_size 345
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -14,8 +14,6 @@ static void WiFiEvent(WiFiEvent_t event);
|
||||
// DNS Server for the Captive Portal
|
||||
DNSServer dnsServer;
|
||||
|
||||
static WiFiServerPort *apiPort;
|
||||
|
||||
uint8_t wifiDisconnectReason = 0;
|
||||
|
||||
// Stores our hostname
|
||||
@@ -180,14 +178,7 @@ void initWifi(bool forceSoftAP)
|
||||
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
|
||||
static void WiFiEvent(WiFiEvent_t event)
|
||||
|
||||
@@ -18,8 +18,8 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc
|
||||
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize);
|
||||
if (!pb_encode(&stream, fields, src_struct)) {
|
||||
DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
assert(0); // FIXME - panic
|
||||
DEBUG_MSG("Panic: can't encode protobuf %s, did you make a field too large?\n", PB_GET_ERROR(&stream));
|
||||
assert(0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options
|
||||
} else {
|
||||
return stream.bytes_written;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0]))
|
||||
|
||||
/// 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
|
||||
/// returns the encoded packet size
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
#include "configuration.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)
|
||||
{
|
||||
DEBUG_MSG("Incoming wifi connection\n");
|
||||
@@ -50,7 +61,7 @@ WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM), concurrency::
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -48,3 +48,5 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
|
||||
|
||||
int32_t runOnce();
|
||||
};
|
||||
|
||||
void initApiServer();
|
||||
|
||||
@@ -224,7 +224,8 @@ void NRF52Bluetooth::setup()
|
||||
|
||||
// Configure and Start the Device Information Service
|
||||
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.setFirmwareRev(optstr(APP_VERSION));
|
||||
bledis.begin();
|
||||
|
||||
@@ -82,8 +82,34 @@ extern "C" void HardFault_Impl(uint32_t stack[])
|
||||
// while (1) ;
|
||||
}
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
// This is a generic cortex M entrypoint that doesn't assume freertos
|
||||
|
||||
extern "C" void HardFault_Handler(void)
|
||||
{
|
||||
asm volatile(" mrs r0,msp\n"
|
||||
" b HardFault_Impl \n");
|
||||
}
|
||||
#else
|
||||
|
||||
/* The prototype shows it is a naked function - in effect this is just an
|
||||
assembly function. */
|
||||
extern "C" void HardFault_Handler( void ) __attribute__( ( naked ) );
|
||||
|
||||
/* The fault handler implementation calls a function called
|
||||
prvGetRegistersFromStack(). */
|
||||
extern "C" void HardFault_Handler(void)
|
||||
{
|
||||
__asm volatile
|
||||
(
|
||||
" tst lr, #4 \n"
|
||||
" ite eq \n"
|
||||
" mrseq r0, msp \n"
|
||||
" mrsne r0, psp \n"
|
||||
" ldr r1, [r0, #24] \n"
|
||||
" ldr r2, handler2_address_const \n"
|
||||
" bx r2 \n"
|
||||
" handler2_address_const: .word HardFault_Impl \n"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "graphics/TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
@@ -51,14 +52,14 @@ void getMacAddr(uint8_t *dmac)
|
||||
NRF52Bluetooth *nrf52Bluetooth;
|
||||
|
||||
static bool bleOn = false;
|
||||
static const bool enableBle = false; // Set to false for easier debugging
|
||||
static const bool useSoftDevice = false; // Set to false for easier debugging
|
||||
|
||||
void setBluetoothEnable(bool on)
|
||||
{
|
||||
if (on != bleOn) {
|
||||
if (on) {
|
||||
if (!nrf52Bluetooth) {
|
||||
if (!enableBle)
|
||||
if (!useSoftDevice)
|
||||
DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n");
|
||||
else {
|
||||
nrf52Bluetooth = new NRF52Bluetooth();
|
||||
@@ -87,6 +88,49 @@ int printf(const char *fmt, ...)
|
||||
|
||||
#include "BQ25713.h"
|
||||
|
||||
void initBrownout()
|
||||
{
|
||||
auto vccthresh = POWER_POFCON_THRESHOLD_V28;
|
||||
auto vcchthresh = POWER_POFCON_THRESHOLDVDDH_V27;
|
||||
|
||||
if (useSoftDevice) {
|
||||
auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled);
|
||||
assert(err_code == NRF_SUCCESS);
|
||||
|
||||
err_code = sd_power_pof_threshold_set(vccthresh);
|
||||
assert(err_code == NRF_SUCCESS);
|
||||
}
|
||||
else {
|
||||
NRF_POWER->POFCON = POWER_POFCON_POF_Msk | (vccthresh << POWER_POFCON_THRESHOLD_Pos) | (vcchthresh << POWER_POFCON_THRESHOLDVDDH_Pos);
|
||||
}
|
||||
}
|
||||
|
||||
void checkSDEvents()
|
||||
{
|
||||
if (useSoftDevice) {
|
||||
uint32_t evt;
|
||||
while (NRF_ERROR_NOT_FOUND == sd_evt_get(&evt)) {
|
||||
switch (evt) {
|
||||
case NRF_EVT_POWER_FAILURE_WARNING:
|
||||
recordCriticalError(CriticalErrorCode_Brownout);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_MSG("Unexpected SDevt %d\n", evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(NRF_POWER->EVENTS_POFWARN)
|
||||
recordCriticalError(CriticalErrorCode_Brownout);
|
||||
}
|
||||
}
|
||||
|
||||
void nrf52Loop()
|
||||
{
|
||||
checkSDEvents();
|
||||
}
|
||||
|
||||
void nrf52Setup()
|
||||
{
|
||||
|
||||
@@ -112,6 +156,8 @@ void nrf52Setup()
|
||||
// randomSeed(r);
|
||||
DEBUG_MSG("FIXME, call randomSeed\n");
|
||||
// ::printf("TESTING PRINTF\n");
|
||||
|
||||
initBrownout();
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint64_t msecToWake)
|
||||
@@ -128,7 +174,7 @@ void cpuDeepSleep(uint64_t msecToWake)
|
||||
// https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
|
||||
|
||||
auto ok = sd_power_system_off();
|
||||
if(ok != NRF_SUCCESS) {
|
||||
if (ok != NRF_SUCCESS) {
|
||||
DEBUG_MSG("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n");
|
||||
NRF_POWER->SYSTEMOFF = 1;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,15 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifdef PORTDUINO
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
AdminPlugin *adminPlugin;
|
||||
|
||||
void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex) {
|
||||
if (req.decoded.want_response) {
|
||||
void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
|
||||
{
|
||||
if (req.decoded.want_response) {
|
||||
// We create the reply here
|
||||
AdminMessage r = AdminMessage_init_default;
|
||||
r.get_channel_response = channels.getByIndex(channelIndex);
|
||||
@@ -23,7 +28,13 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req)
|
||||
if (req.decoded.want_response) {
|
||||
// We create the reply here
|
||||
AdminMessage r = AdminMessage_init_default;
|
||||
r.get_radio_response = devicestate.radio;
|
||||
r.get_radio_response = radioConfig;
|
||||
|
||||
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
|
||||
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
|
||||
// using to the app (so that even old phone apps work with new device loads).
|
||||
r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
|
||||
|
||||
r.which_variant = AdminMessage_get_radio_response_tag;
|
||||
reply = allocDataProtobuf(r);
|
||||
}
|
||||
@@ -44,7 +55,7 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag
|
||||
break;
|
||||
|
||||
case AdminMessage_set_channel_tag:
|
||||
DEBUG_MSG("Client is setting channel\n");
|
||||
DEBUG_MSG("Client is setting channel %d\n", r->set_channel.index);
|
||||
handleSetChannel(r->set_channel);
|
||||
break;
|
||||
|
||||
@@ -58,7 +69,16 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag
|
||||
handleGetRadio(mp);
|
||||
break;
|
||||
|
||||
#ifdef PORTDUINO
|
||||
case AdminMessage_exit_simulator_tag:
|
||||
DEBUG_MSG("Exiting simulator\n");
|
||||
_exit(0);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
// Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages
|
||||
DEBUG_MSG("Ignoring nonrelevant admin %d\n", r->which_variant);
|
||||
break;
|
||||
}
|
||||
return false; // Let others look at this message also if they want
|
||||
@@ -89,21 +109,21 @@ void AdminPlugin::handleSetChannel(const Channel &cc)
|
||||
{
|
||||
channels.setChannel(cc);
|
||||
|
||||
bool didReset = service.reloadConfig();
|
||||
/* FIXME - do we need this still?
|
||||
if (didReset) {
|
||||
state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client
|
||||
} */
|
||||
// Just update and save the channels - no need to update the radio for ! primary channel changes
|
||||
if (cc.index == 0) {
|
||||
// FIXME, this updates the user preferences also, which isn't needed - we really just want to notify on configChanged
|
||||
service.reloadConfig();
|
||||
} else {
|
||||
channels.onConfigChanged(); // tell the radios about this change
|
||||
nodeDB.saveChannelsToDisk();
|
||||
}
|
||||
}
|
||||
|
||||
void AdminPlugin::handleSetRadio(const RadioConfig &r)
|
||||
{
|
||||
radioConfig = r;
|
||||
|
||||
bool didReset = service.reloadConfig();
|
||||
/* FIXME - do we need this still? if (didReset) {
|
||||
state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client
|
||||
} */
|
||||
service.reloadConfig();
|
||||
}
|
||||
|
||||
MeshPacket *AdminPlugin::allocReply()
|
||||
@@ -115,5 +135,6 @@ MeshPacket *AdminPlugin::allocReply()
|
||||
|
||||
AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
||||
{
|
||||
// FIXME, restrict to the admin channel for rx
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::adminChannel;
|
||||
}
|
||||
|
||||
@@ -43,25 +43,17 @@
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// Default configurations
|
||||
#define EXT_NOTIFICATION_PLUGIN_OUTPUT 13
|
||||
#define EXT_NOTIFICATION_PLUGIN_OUTPUT_MS 1000
|
||||
|
||||
#define ASCII_BELL 0x07
|
||||
|
||||
ExternalNotificationPlugin *externalNotificationPlugin;
|
||||
ExternalNotificationPluginRadio *externalNotificationPluginRadio;
|
||||
|
||||
ExternalNotificationPlugin::ExternalNotificationPlugin() : concurrency::OSThread("ExternalNotificationPlugin") {}
|
||||
|
||||
bool externalCurrentState = 0;
|
||||
uint32_t externalTurnedOn = 0;
|
||||
|
||||
int32_t ExternalNotificationPlugin::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
@@ -75,47 +67,19 @@ int32_t ExternalNotificationPlugin::runOnce()
|
||||
// radioConfig.preferences.ext_notification_plugin_output_ms = 1000;
|
||||
// radioConfig.preferences.ext_notification_plugin_output = 13;
|
||||
|
||||
if (radioConfig.preferences.ext_notification_plugin_enabled) {
|
||||
if (externalCurrentState) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
DEBUG_MSG("Initializing External Notification Plugin\n");
|
||||
|
||||
// Set the direction of a pin
|
||||
pinMode((radioConfig.preferences.ext_notification_plugin_output
|
||||
? radioConfig.preferences.ext_notification_plugin_output
|
||||
: EXT_NOTIFICATION_PLUGIN_OUTPUT),
|
||||
OUTPUT);
|
||||
|
||||
// Turn off the pin
|
||||
// If the output is turned on, turn it back off after the given period of time.
|
||||
if (externalTurnedOn + (radioConfig.preferences.ext_notification_plugin_output_ms
|
||||
? radioConfig.preferences.ext_notification_plugin_output_ms
|
||||
: EXT_NOTIFICATION_PLUGIN_OUTPUT_MS) <
|
||||
millis()) {
|
||||
DEBUG_MSG("Turning off external notification\n");
|
||||
setExternalOff();
|
||||
|
||||
externalNotificationPluginRadio = new ExternalNotificationPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
} else {
|
||||
if (externalCurrentState) {
|
||||
|
||||
// If the output is turned on, turn it back off after the given period of time.
|
||||
if (externalTurnedOn + (radioConfig.preferences.ext_notification_plugin_output_ms
|
||||
? radioConfig.preferences.ext_notification_plugin_output_ms
|
||||
: EXT_NOTIFICATION_PLUGIN_OUTPUT_MS) <
|
||||
millis()) {
|
||||
DEBUG_MSG("Turning off external notification\n");
|
||||
setExternalOff();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (25);
|
||||
} else {
|
||||
DEBUG_MSG("External Notification Plugin Disabled\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
#endif
|
||||
return (25);
|
||||
}
|
||||
|
||||
void ExternalNotificationPlugin::setExternalOn()
|
||||
@@ -139,7 +103,47 @@ void ExternalNotificationPlugin::setExternalOff()
|
||||
|
||||
// --------
|
||||
|
||||
bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
ExternalNotificationPlugin::ExternalNotificationPlugin()
|
||||
: SinglePortPlugin("ExternalNotificationPlugin", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread(
|
||||
"ExternalNotificationPlugin")
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::gpioChannel;
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// radioConfig.preferences.ext_notification_plugin_enabled = 1;
|
||||
// radioConfig.preferences.ext_notification_plugin_alert_message = 1;
|
||||
|
||||
// radioConfig.preferences.ext_notification_plugin_active = 1;
|
||||
// radioConfig.preferences.ext_notification_plugin_alert_bell = 1;
|
||||
// radioConfig.preferences.ext_notification_plugin_output_ms = 1000;
|
||||
// radioConfig.preferences.ext_notification_plugin_output = 13;
|
||||
|
||||
if (radioConfig.preferences.ext_notification_plugin_enabled) {
|
||||
|
||||
DEBUG_MSG("Initializing External Notification Plugin\n");
|
||||
|
||||
// Set the direction of a pin
|
||||
pinMode((radioConfig.preferences.ext_notification_plugin_output ? radioConfig.preferences.ext_notification_plugin_output
|
||||
: EXT_NOTIFICATION_PLUGIN_OUTPUT),
|
||||
OUTPUT);
|
||||
|
||||
// Turn off the pin
|
||||
setExternalOff();
|
||||
} else {
|
||||
DEBUG_MSG("External Notification Plugin Disabled\n");
|
||||
enabled = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ExternalNotificationPlugin::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
@@ -147,7 +151,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
auto &p = mp.decoded;
|
||||
|
||||
if (mp.from != nodeDB.getNodeNum()) {
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
|
||||
// TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
|
||||
// Need to know if and how this could be a problem.
|
||||
@@ -155,14 +159,14 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
DEBUG_MSG("externalNotificationPlugin - Notification Bell\n");
|
||||
for (int i = 0; i < p.payload.size; i++) {
|
||||
if (p.payload.bytes[i] == ASCII_BELL) {
|
||||
externalNotificationPlugin->setExternalOn();
|
||||
setExternalOn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (radioConfig.preferences.ext_notification_plugin_alert_message) {
|
||||
DEBUG_MSG("externalNotificationPlugin - Notification Plugin\n");
|
||||
externalNotificationPlugin->setExternalOn();
|
||||
setExternalOn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
|
||||
class ExternalNotificationPlugin : private concurrency::OSThread
|
||||
/*
|
||||
* Radio interface for ExternalNotificationPlugin
|
||||
*
|
||||
*/
|
||||
class ExternalNotificationPlugin : public SinglePortPlugin, private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
public:
|
||||
ExternalNotificationPlugin();
|
||||
|
||||
@@ -19,29 +20,13 @@ class ExternalNotificationPlugin : private concurrency::OSThread
|
||||
void getExternal();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
extern ExternalNotificationPlugin *externalNotificationPlugin;
|
||||
|
||||
/*
|
||||
* Radio interface for ExternalNotificationPlugin
|
||||
*
|
||||
*/
|
||||
class ExternalNotificationPluginRadio : public SinglePortPlugin
|
||||
{
|
||||
|
||||
public:
|
||||
ExternalNotificationPluginRadio() : SinglePortPlugin("ExternalNotificationPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
protected:
|
||||
//virtual MeshPacket *allocReply();
|
||||
// virtual MeshPacket *allocReply();
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern ExternalNotificationPluginRadio *externalNotificationPluginRadio;
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
@@ -12,16 +12,18 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User *pp
|
||||
{
|
||||
auto p = *pptr;
|
||||
|
||||
nodeDB.updateUser(mp.from, p);
|
||||
nodeDB.updateUser(getFrom(&mp), p);
|
||||
|
||||
bool wasBroadcast = mp.to == NODENUM_BROADCAST;
|
||||
|
||||
// Show new nodes on LCD screen
|
||||
if (wasBroadcast) {
|
||||
String lcd = String("Joined: ") + p.long_name + "\n";
|
||||
screen->print(lcd.c_str());
|
||||
if(screen)
|
||||
screen->print(lcd.c_str());
|
||||
}
|
||||
|
||||
// DEBUG_MSG("did handleReceived\n");
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
@@ -65,8 +67,7 @@ int32_t NodeInfoPlugin::runOnce()
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
|
||||
assert(nodeInfoPlugin);
|
||||
nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
|
||||
sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
|
||||
|
||||
return getPref_position_broadcast_secs() * 1000;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
void setupPlugins()
|
||||
{
|
||||
routingPlugin = new RoutingPlugin();
|
||||
adminPlugin = new AdminPlugin();
|
||||
nodeInfoPlugin = new NodeInfoPlugin();
|
||||
positionPlugin = new PositionPlugin();
|
||||
@@ -48,4 +47,7 @@ void setupPlugins()
|
||||
// new StoreForwardPlugin();
|
||||
new EnvironmentalMeasurementPlugin();
|
||||
#endif
|
||||
|
||||
// NOTE! This plugin must be added LAST because it likes to check for replies from other plugins and avoid sending extra acks
|
||||
routingPlugin = new RoutingPlugin();
|
||||
}
|
||||
@@ -30,7 +30,7 @@ bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position
|
||||
perhapsSetRTC(RTCQualityFromNet, &tv);
|
||||
}
|
||||
|
||||
nodeDB.updatePosition(mp.from, p);
|
||||
nodeDB.updatePosition(getFrom(&mp), p);
|
||||
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@ bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const H
|
||||
|
||||
case HardwareMessage_Type_READ_GPIOS: {
|
||||
// Print notification to LCD screen
|
||||
screen->print("Read GPIOs\n");
|
||||
if(screen)
|
||||
screen->print("Read GPIOs\n");
|
||||
|
||||
uint64_t res = digitalReads(p.gpio_mask);
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ RoutingPlugin *routingPlugin;
|
||||
|
||||
bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *r)
|
||||
{
|
||||
DEBUG_MSG("Routing sniffing", &mp);
|
||||
printPacket("Routing sniffing", &mp);
|
||||
router->sniffReceived(&mp, r);
|
||||
|
||||
// FIXME - move this to a non promsicious PhoneAPI plugin?
|
||||
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) {
|
||||
// Note: we are careful not to send back packets that started with the phone back to the phone
|
||||
if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) {
|
||||
printPacket("Delivering rx packet", &mp);
|
||||
service.handleFromRadio(&mp);
|
||||
}
|
||||
@@ -34,7 +35,7 @@ MeshPacket *RoutingPlugin::allocReply()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom)
|
||||
void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
{
|
||||
Routing c = Routing_init_default;
|
||||
|
||||
@@ -46,6 +47,7 @@ void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom)
|
||||
p->hop_limit = 0; // Assume just immediate neighbors for now
|
||||
p->to = to;
|
||||
p->decoded.request_id = idFrom;
|
||||
p->channel = chIndex;
|
||||
DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
|
||||
router->sendLocal(p); // we sometimes send directly to the local node
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "ProtobufPlugin.h"
|
||||
#include "Channels.h"
|
||||
|
||||
/**
|
||||
* Routing plugin for router control messages
|
||||
@@ -12,6 +13,8 @@ class RoutingPlugin : public ProtobufPlugin<Routing>
|
||||
*/
|
||||
RoutingPlugin();
|
||||
|
||||
void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
|
||||
|
||||
protected:
|
||||
friend class Router;
|
||||
|
||||
@@ -27,8 +30,6 @@ class RoutingPlugin : public ProtobufPlugin<Routing>
|
||||
|
||||
/// Override wantPacket to say we want to see all packets, not just those for our port number
|
||||
virtual bool wantPacket(const MeshPacket *p) { return true; }
|
||||
|
||||
void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom);
|
||||
};
|
||||
|
||||
extern RoutingPlugin *routingPlugin;
|
||||
@@ -61,6 +61,12 @@ SerialPlugin::SerialPlugin() : concurrency::OSThread("SerialPlugin") {}
|
||||
|
||||
char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
|
||||
SerialPluginRadio::SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP)
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::serialChannel;
|
||||
}
|
||||
|
||||
int32_t SerialPlugin::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
@@ -124,7 +130,8 @@ int32_t SerialPlugin::runOnce()
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
#else
|
||||
return INT32_MAX;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -160,7 +167,7 @@ bool SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
if (mp.from == nodeDB.getNodeNum()) {
|
||||
if (getFrom(&mp) == nodeDB.getNodeNum()) {
|
||||
|
||||
/*
|
||||
* If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX
|
||||
|
||||
@@ -33,8 +33,7 @@ class SerialPluginRadio : public SinglePortPlugin
|
||||
from the main code.
|
||||
*/
|
||||
|
||||
// SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {}
|
||||
SerialPluginRadio();
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
|
||||
@@ -8,7 +8,7 @@ TextMessagePlugin *textMessagePlugin;
|
||||
bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
|
||||
DEBUG_MSG("Received text msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
// We only store/display messages destined for us.
|
||||
// Keep a copy of the most recent text message.
|
||||
|
||||
@@ -10,20 +10,10 @@
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin;
|
||||
EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
|
||||
|
||||
EnvironmentalMeasurementPlugin::EnvironmentalMeasurementPlugin() : concurrency::OSThread("EnvironmentalMeasurementPlugin") {}
|
||||
|
||||
uint32_t sensor_read_error_count = 0;
|
||||
|
||||
#define DHT_11_GPIO_PIN 13
|
||||
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 // Some sensors (the DHT11) have a minimum required duration between read attempts
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
|
||||
DHT dht(DHT_11_GPIO_PIN,DHT11);
|
||||
|
||||
|
||||
#ifdef HAS_EINK
|
||||
// The screen is bigger so use bigger fonts
|
||||
@@ -49,11 +39,15 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
/*radioConfig.preferences.environmental_measurement_plugin_measurement_enabled = 1;
|
||||
radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1;
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5;
|
||||
radioConfig.preferences.environmental_measurement_plugin_update_interval = 30;
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 60;
|
||||
radioConfig.preferences.environmental_measurement_plugin_display_farenheit = true;
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_pin = 13;
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_type = RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType::RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11;*/
|
||||
|
||||
if (! (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
|
||||
// If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
|
||||
@@ -62,20 +56,32 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do some setup
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Initializing\n");
|
||||
environmentalMeasurementPluginRadio = new EnvironmentalMeasurementPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
// begin reading measurements from the sensor
|
||||
// DHT have a max read-rate of 1HZ, so we should wait at least 1 second
|
||||
// after initializing the sensor before we try to read from it.
|
||||
// returning the interval here means that the next time OSThread
|
||||
// calls our plugin, we'll run the other branch of this if statement
|
||||
// and actually do a "sendOurEnvironmentalMeasurement()"
|
||||
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled)
|
||||
{
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Initializing\n");
|
||||
// it's possible to have this plugin enabled, only for displaying values on the screen.
|
||||
// therefore, we should only enable the sensor loop if measurement is also enabled
|
||||
dht.begin();
|
||||
switch(radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
dht = new DHT(radioConfig.preferences.environmental_measurement_plugin_sensor_pin,DHT11);
|
||||
this->dht->begin();
|
||||
this->dht->read();
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened DHT11 on pin: %d\n",radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin");
|
||||
return (INT32_MAX);
|
||||
break;
|
||||
}
|
||||
// begin reading measurements from the sensor
|
||||
// DHT have a max read-rate of 1HZ, so we should wait at least 1 second
|
||||
// after initializing the sensor before we try to read from it.
|
||||
// returning the interval here means that the next time OSThread
|
||||
// calls our plugin, we'll run the other branch of this if statement
|
||||
// and actually do a "sendOurEnvironmentalMeasurement()"
|
||||
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
return (INT32_MAX);
|
||||
@@ -96,6 +102,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||
"EnvironmentalMeasurement: TEMPORARILY DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in %d seconds\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold,
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval);
|
||||
sensor_read_error_count = 0;
|
||||
return(radioConfig.preferences.environmental_measurement_plugin_recovery_interval*1000);
|
||||
}
|
||||
DEBUG_MSG(
|
||||
@@ -110,7 +117,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||
sensor_read_error_count,
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold-sensor_read_error_count);
|
||||
}
|
||||
if (! environmentalMeasurementPluginRadio->sendOurEnvironmentalMeasurement() ){
|
||||
if (!sendOurEnvironmentalMeasurement() ){
|
||||
// if we failed to read the sensor, then try again
|
||||
// as soon as we can according to the maximum polling frequency
|
||||
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
@@ -123,25 +130,16 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPluginRadio::wantUIFrame() {
|
||||
bool EnvironmentalMeasurementPlugin::wantUIFrame() {
|
||||
return radioConfig.preferences.environmental_measurement_plugin_screen_enabled;
|
||||
}
|
||||
|
||||
void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(x, y, "Environment");
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": T:"+ String(lastMeasurement.temperature,2) + " H:" + String(lastMeasurement.relative_humidity,2));
|
||||
|
||||
}
|
||||
|
||||
String GetSenderName(const MeshPacket &mp) {
|
||||
String sender;
|
||||
|
||||
if (nodeDB.getNode(mp.from)){
|
||||
sender = nodeDB.getNode(mp.from)->user.short_name;
|
||||
auto node = nodeDB.getNode(getFrom(&mp));
|
||||
if (node){
|
||||
sender = node->user.short_name;
|
||||
}
|
||||
else {
|
||||
sender = "UNK";
|
||||
@@ -149,55 +147,99 @@ String GetSenderName(const MeshPacket &mp) {
|
||||
return sender;
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *pptr)
|
||||
uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp) {
|
||||
uint32_t now = getTime();
|
||||
|
||||
uint32_t last_seen = mp->rx_time;
|
||||
int delta = (int)(now - last_seen);
|
||||
if (delta < 0) // our clock must be slightly off still - not set from GPS yet
|
||||
delta = 0;
|
||||
|
||||
return delta;
|
||||
|
||||
}
|
||||
|
||||
|
||||
float EnvironmentalMeasurementPlugin::CelsiusToFarenheit(float c) {
|
||||
return (c*9)/5 + 32;
|
||||
}
|
||||
|
||||
|
||||
void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
const EnvironmentalMeasurement &p = *pptr;
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(x, y, "Environment");
|
||||
if (lastMeasurementPacket == nullptr) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement");
|
||||
//DEBUG_MSG("EnvironmentalMeasurement: No previous measurement; not drawing frame\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EnvironmentalMeasurement lastMeasurement;
|
||||
|
||||
|
||||
uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket);
|
||||
String lastSender = GetSenderName(*lastMeasurementPacket);
|
||||
|
||||
auto &p = lastMeasurementPacket->decoded;
|
||||
if (!pb_decode_from_bytes(p.payload.bytes,
|
||||
p.payload.size,
|
||||
EnvironmentalMeasurement_fields,
|
||||
&lastMeasurement)) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
|
||||
DEBUG_MSG("EnvironmentalMeasurement: unable to decode last packet");
|
||||
return;
|
||||
}
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
String last_temp = String(lastMeasurement.temperature,0) +"°C";
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_display_farenheit){
|
||||
last_temp = String(CelsiusToFarenheit(lastMeasurement.temperature),0) +"°F";;
|
||||
}
|
||||
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": "+last_temp +"/"+ String(lastMeasurement.relative_humidity,0) + "%("+String(agoSecs)+"s)");
|
||||
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p)
|
||||
{
|
||||
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
|
||||
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
|
||||
return false;
|
||||
}
|
||||
bool wasBroadcast = mp.to == NODENUM_BROADCAST;
|
||||
|
||||
String sender = GetSenderName(mp);
|
||||
|
||||
// Show new nodes on LCD screen
|
||||
if (DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN && wasBroadcast) {
|
||||
String lcd = String("Env Measured: ") +sender + "\n" +
|
||||
"T: " + p.temperature + "\n" +
|
||||
"H: " + p.relative_humidity + "\n";
|
||||
screen->print(lcd.c_str());
|
||||
}
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n", sender);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p->relative_humidity);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p->temperature);
|
||||
|
||||
lastMeasurementPacket = packetPool.allocCopy(mp);
|
||||
|
||||
lastMeasurement = p;
|
||||
lastSender = sender;
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies)
|
||||
bool EnvironmentalMeasurementPlugin::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
EnvironmentalMeasurement m;
|
||||
|
||||
m.barometric_pressure = 0; // TODO: Add support for barometric sensors
|
||||
m.relative_humidity = dht.readHumidity();
|
||||
m.temperature = dht.readTemperature();;
|
||||
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Read data\n");
|
||||
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature);
|
||||
|
||||
if (isnan(m.relative_humidity) || isnan(m.temperature) ){
|
||||
if (!this->dht->read(true)){
|
||||
sensor_read_error_count++;
|
||||
DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n");
|
||||
return false;
|
||||
}
|
||||
m.relative_humidity = this->dht->readHumidity();
|
||||
m.temperature = this->dht->readTemperature();
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature);
|
||||
|
||||
sensor_read_error_count = 0;
|
||||
|
||||
|
||||
@@ -3,61 +3,32 @@
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
#include <DHT.h>
|
||||
|
||||
|
||||
class EnvironmentalMeasurementPlugin : private concurrency::OSThread
|
||||
class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public ProtobufPlugin<EnvironmentalMeasurement>
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
public:
|
||||
EnvironmentalMeasurementPlugin();
|
||||
EnvironmentalMeasurementPlugin(): concurrency::OSThread("EnvironmentalMeasurementPlugin"), ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) {
|
||||
lastMeasurementPacket = nullptr;
|
||||
}
|
||||
virtual bool wantUIFrame();
|
||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p);
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
extern EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin;
|
||||
|
||||
/**
|
||||
* EnvironmentalMeasurementPluginRadio plugin for sending/receiving environmental measurements to/from the mesh
|
||||
*/
|
||||
class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin<EnvironmentalMeasurement>
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
EnvironmentalMeasurementPluginRadio() : ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) {
|
||||
lastMeasurement.barometric_pressure = nanf("");
|
||||
lastMeasurement.relative_humidity = nanf("");
|
||||
lastMeasurement.temperature = nanf("");
|
||||
lastSender = "N/A";
|
||||
}
|
||||
|
||||
/**
|
||||
* Send our EnvironmentalMeasurement into the mesh
|
||||
*/
|
||||
bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
protected:
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p);
|
||||
|
||||
virtual bool wantUIFrame();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EnvironmentalMeasurement lastMeasurement;
|
||||
|
||||
String lastSender;
|
||||
|
||||
};
|
||||
|
||||
extern EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
|
||||
float CelsiusToFarenheit(float c);
|
||||
bool firstTime = 1;
|
||||
DHT* dht;
|
||||
const MeshPacket *lastMeasurementPacket;
|
||||
uint32_t sensor_read_error_count = 0;
|
||||
};
|
||||
@@ -133,7 +133,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
if (mp.from != nodeDB.getNodeNum()) {
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
@@ -144,7 +144,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
*/
|
||||
|
||||
NodeInfo *n = nodeDB.getNode(mp.from);
|
||||
NodeInfo *n = nodeDB.getNode(getFrom(&mp));
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_save) {
|
||||
appendFile(mp);
|
||||
@@ -209,7 +209,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
|
||||
NodeInfo *n = nodeDB.getNode(mp.from);
|
||||
NodeInfo *n = nodeDB.getNode(getFrom(&mp));
|
||||
/*
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
||||
@@ -290,7 +290,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
fileToAppend.printf("??:??:??,"); // Time
|
||||
}
|
||||
|
||||
fileToAppend.printf("%d,", mp.from); // From
|
||||
fileToAppend.printf("%d,", getFrom(&mp)); // From
|
||||
fileToAppend.printf("%s,", n->user.long_name); // Long Name
|
||||
fileToAppend.printf("%f,", n->position.latitude_i * 1e-7); // Sender Lat
|
||||
fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long
|
||||
|
||||
@@ -8,79 +8,36 @@
|
||||
#include <Arduino.h>
|
||||
#include <map>
|
||||
|
||||
#define STOREFORWARD_MAX_PACKETS 7500
|
||||
#define STOREFORWARD_MAX_PACKETS 0
|
||||
#define STOREFORWARD_SEND_HISTORY_SHORT 600
|
||||
|
||||
StoreForwardPlugin *storeForwardPlugin;
|
||||
StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
|
||||
StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPlugin") {}
|
||||
|
||||
int32_t StoreForwardPlugin::runOnce()
|
||||
{
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
// radioConfig.preferences.is_router = 1;
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
if (radioConfig.preferences.is_router) {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled\n");
|
||||
// Router
|
||||
if (ESP.getPsramSize()) {
|
||||
if (ESP.getFreePsram() >= 2048 * 1024) {
|
||||
// Do the startup here
|
||||
storeForwardPluginRadio = new StoreForwardPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
this->populatePSRAM();
|
||||
|
||||
// packetHistory[0].bytes;
|
||||
return (10 * 1000);
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 2M of PSRAM free. Aborting startup.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device doesn't have PSRAM.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled but is_router is not turned on.\n");
|
||||
DEBUG_MSG(
|
||||
"Initializing Store & Forward Plugin - If you want to use this plugin, you must also turn on is_router.\n");
|
||||
// Non-Router
|
||||
|
||||
return (30 * 1000);
|
||||
}
|
||||
|
||||
} else {
|
||||
// What do we do if it's not our first time?
|
||||
|
||||
if (radioConfig.preferences.is_router) {
|
||||
// Maybe some cleanup functions?
|
||||
this->sawNodeReport();
|
||||
this->historyReport();
|
||||
return (10 * 1000);
|
||||
} else {
|
||||
/*
|
||||
* If the plugin is turned on and is_router is not enabled, then we'll send a heartbeat every
|
||||
* few minutes.
|
||||
*
|
||||
* This behavior is expected to change. It's only here until we come up with something better.
|
||||
*/
|
||||
|
||||
DEBUG_MSG("Store & Forward Plugin - Sending heartbeat\n");
|
||||
|
||||
storeForwardPlugin->sendPayload();
|
||||
|
||||
return (4 * 60 * 1000);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -100,24 +57,29 @@ void StoreForwardPlugin::populatePSRAM()
|
||||
https://learn.upesy.com/en/programmation/psram.html#psram-tab
|
||||
*/
|
||||
|
||||
DEBUG_MSG("Before PSRAM initilization\n");
|
||||
DEBUG_MSG("Before PSRAM initilization:\n");
|
||||
|
||||
DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize());
|
||||
DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap());
|
||||
DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize());
|
||||
DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram());
|
||||
DEBUG_MSG(" Total heap: %d\n", ESP.getHeapSize());
|
||||
DEBUG_MSG(" Free heap: %d\n", ESP.getFreeHeap());
|
||||
DEBUG_MSG(" Total PSRAM: %d\n", ESP.getPsramSize());
|
||||
DEBUG_MSG(" Free PSRAM: %d\n", ESP.getFreePsram());
|
||||
|
||||
// PacketHistoryStruct *packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS,
|
||||
// sizeof(PacketHistoryStruct));
|
||||
this->packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, sizeof(PacketHistoryStruct));
|
||||
DEBUG_MSG("After PSRAM initilization\n");
|
||||
|
||||
DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize());
|
||||
DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap());
|
||||
DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize());
|
||||
DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram());
|
||||
// Use a maximum of half the available PSRAM unless otherwise specified.
|
||||
uint32_t numberOfPackets =
|
||||
STOREFORWARD_MAX_PACKETS ? STOREFORWARD_MAX_PACKETS : ((ESP.getPsramSize() / 2) / sizeof(PacketHistoryStruct));
|
||||
|
||||
DEBUG_MSG("packetHistory Size - %u", sizeof(packetHistory));
|
||||
this->packetHistory = (PacketHistoryStruct *)ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct));
|
||||
DEBUG_MSG("After PSRAM initilization:\n");
|
||||
|
||||
DEBUG_MSG(" Total heap: %d\n", ESP.getHeapSize());
|
||||
DEBUG_MSG(" Free heap: %d\n", ESP.getFreeHeap());
|
||||
DEBUG_MSG(" Total PSRAM: %d\n", ESP.getPsramSize());
|
||||
DEBUG_MSG(" Free PSRAM: %d\n", ESP.getFreePsram());
|
||||
DEBUG_MSG("Store and Forward Stats:\n");
|
||||
DEBUG_MSG(" numberOfPackets - %u\n", numberOfPackets);
|
||||
}
|
||||
|
||||
// We saw a node.
|
||||
@@ -218,36 +180,44 @@ void StoreForwardPlugin::sawNodeReport()
|
||||
}
|
||||
}
|
||||
|
||||
MeshPacket *StoreForwardPluginRadio::allocReply()
|
||||
MeshPacket *StoreForwardPlugin::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
void StoreForwardPlugin::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
DEBUG_MSG("Sending S&F Payload\n");
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = true;
|
||||
/*
|
||||
*/
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "1");
|
||||
|
||||
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, "1", 1);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
bool StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
if (mp.from != nodeDB.getNodeNum()) {
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
// DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n");
|
||||
// DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
// p->want_ack, p->hop_limit);
|
||||
printPacket("----- PACKET FROM RADIO -----", &mp);
|
||||
uint32_t sawTime = storeForwardPlugin->sawNode(mp.from & 0xffffffff);
|
||||
uint32_t sawTime = storeForwardPlugin->sawNode(getFrom(&mp) & 0xffffffff);
|
||||
DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from & 0xffffffff, (millis() - sawTime) / 1000);
|
||||
|
||||
DEBUG_MSG(" -------------- ");
|
||||
if (mp.decoded.portnum == PortNum_UNKNOWN_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_UNKNOWN_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
|
||||
@@ -282,7 +252,7 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
}
|
||||
|
||||
if ((millis() - sawTime) > STOREFORWARD_SEND_HISTORY_SHORT) {
|
||||
// Node has been away for a while.
|
||||
// Node has been away for a while.
|
||||
storeForwardPlugin->historySend(sawTime, mp.from);
|
||||
}
|
||||
}
|
||||
@@ -295,3 +265,52 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
StoreForwardPlugin::StoreForwardPlugin()
|
||||
: SinglePortPlugin("StoreForwardPlugin", PortNum_STORE_FORWARD_APP), concurrency::OSThread("StoreForwardPlugin")
|
||||
{
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
|
||||
radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
radioConfig.preferences.is_router = 1;
|
||||
*/
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
if (radioConfig.preferences.is_router) {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Router\n");
|
||||
// Router
|
||||
if (ESP.getPsramSize()) {
|
||||
if (ESP.getFreePsram() >= 2048 * 1024) {
|
||||
// Do the startup here
|
||||
|
||||
this->populatePSRAM();
|
||||
|
||||
// packetHistory[0].bytes;
|
||||
// return (10 * 1000);
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 2M of PSRAM free. Aborting startup.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
|
||||
// return (INT32_MAX);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device doesn't have PSRAM.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
|
||||
// return (INT32_MAX);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Client\n");
|
||||
// return (5 * 1000);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
|
||||
struct PacketHistoryStruct {
|
||||
uint32_t time;
|
||||
uint32_t to;
|
||||
@@ -14,7 +13,7 @@ struct PacketHistoryStruct {
|
||||
uint8_t bytes[MAX_RHPACKETLEN];
|
||||
};
|
||||
|
||||
class StoreForwardPlugin : private concurrency::OSThread
|
||||
class StoreForwardPlugin : public SinglePortPlugin, private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
@@ -37,36 +36,18 @@ class StoreForwardPlugin : private concurrency::OSThread
|
||||
void historySend(uint32_t msAgo, uint32_t to);
|
||||
void populatePSRAM();
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
virtual MeshPacket *allocReply();
|
||||
virtual bool wantPortnum(PortNum p) { return true; };
|
||||
|
||||
private:
|
||||
// Nothing here
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
extern StoreForwardPlugin *storeForwardPlugin;
|
||||
|
||||
/*
|
||||
* Radio interface for StoreForwardPlugin
|
||||
*
|
||||
*/
|
||||
class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
{
|
||||
// uint32_t lastRxID;
|
||||
|
||||
public:
|
||||
StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {}
|
||||
// StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
protected:
|
||||
virtual MeshPacket *allocReply();
|
||||
|
||||
virtual bool wantPortnum(PortNum p) { return true; };
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@@ -75,4 +56,28 @@ class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern StoreForwardPlugin *storeForwardPlugin;
|
||||
|
||||
/*
|
||||
* Radio interface for StoreForwardPlugin
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
{
|
||||
// uint32_t lastRxID;
|
||||
|
||||
public:
|
||||
StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {}
|
||||
// StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
void sendPayloadHeartbeat(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
protected:
|
||||
virtual MeshPacket *allocReply2();
|
||||
};
|
||||
|
||||
extern StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
*/
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ void getMacAddr(uint8_t *dmac)
|
||||
|
||||
void setBluetoothEnable(bool on)
|
||||
{
|
||||
notImplemented("setBluetoothEnable");
|
||||
// not needed
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint64_t msecs) {
|
||||
@@ -88,7 +88,10 @@ public:
|
||||
*/
|
||||
void portduinoSetup() {
|
||||
printf("Setting up Meshtastic on Porduino...\n");
|
||||
gpioBind(new R595PolledIrqPin());
|
||||
|
||||
// FIXME: disable while not testing with real hardware
|
||||
// gpioBind(new R595PolledIrqPin());
|
||||
|
||||
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
|
||||
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
|
||||
}
|
||||
|
||||
@@ -99,16 +99,16 @@ extern "C" {
|
||||
#define NUM_ANALOG_OUTPUTS (0)
|
||||
|
||||
// LEDs
|
||||
#define PIN_LED1 (0 + 13) // red (confirmed on 1.0 board)
|
||||
#define PIN_LED2 (0 + 14) // blue (seems busted!)
|
||||
#define PIN_LED3 (0 + 15) // green (seems busted!)
|
||||
#define PIN_LED1 (0 + 14) // 13 red (confirmed on 1.0 board)
|
||||
#define PIN_LED2 (0 + 15) // 14 blue
|
||||
#define PIN_LED3 (0 + 13) // 15 green
|
||||
|
||||
#define LED_RED PIN_LED3
|
||||
#define LED_GREEN PIN_LED1
|
||||
#define LED_BLUE PIN_LED2
|
||||
#define LED_BLUE PIN_LED1
|
||||
#define LED_GREEN PIN_LED2
|
||||
|
||||
#define LED_BUILTIN LED_GREEN
|
||||
#define LED_CONN PIN_BLUE
|
||||
#define LED_BUILTIN LED_BLUE
|
||||
#define LED_CONN PIN_GREEN
|
||||
|
||||
#define LED_STATE_ON 0 // State when LED is lit
|
||||
#define LED_INVERTED 1
|
||||
@@ -192,6 +192,9 @@ External serial flash WP25R1635FZUIL0
|
||||
|
||||
// #define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...)
|
||||
|
||||
// #undef SX1262_CS
|
||||
// #define USE_SIM_RADIO // define to not use the lora radio hardware at all
|
||||
|
||||
/*
|
||||
* eink display pins
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 1
|
||||
minor = 2
|
||||
build = 1
|
||||
build = 11
|
||||
|
||||
Reference in New Issue
Block a user