mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-15 23:32:34 +00:00
Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
286686137f | ||
|
|
77c1112fe8 | ||
|
|
2d4ba357f7 | ||
|
|
455d0f8d66 | ||
|
|
5b0e7c6e82 | ||
|
|
78c665abb9 | ||
|
|
9a86d52d00 | ||
|
|
c5973f9a55 | ||
|
|
eb684aac03 | ||
|
|
7b4f8fb6d6 | ||
|
|
8065dbb2b7 | ||
|
|
049e791382 | ||
|
|
4fb8552563 | ||
|
|
90576f44d8 | ||
|
|
9e0a2964a4 | ||
|
|
49b16fdf0c | ||
|
|
1fcec8ce3b | ||
|
|
d32386a027 | ||
|
|
9b57d28c7d | ||
|
|
b9fd726c14 | ||
|
|
f165418b18 | ||
|
|
13889124c1 | ||
|
|
9005aaa14e | ||
|
|
df4e325e43 | ||
|
|
4ebc07b691 | ||
|
|
79a8d023ca | ||
|
|
330d83e7c3 | ||
|
|
a74384f3f5 | ||
|
|
da732c291f | ||
|
|
648d9dd19f | ||
|
|
e9faf657df | ||
|
|
103ffde025 | ||
|
|
baeb002245 | ||
|
|
0ce7a3f0ec | ||
|
|
0befad82a7 | ||
|
|
b357d8ae5b | ||
|
|
dd9beff9a5 | ||
|
|
d652664126 | ||
|
|
4666c12547 | ||
|
|
2b74260e2b | ||
|
|
620d336e55 | ||
|
|
e845a3388b | ||
|
|
a25235dc03 | ||
|
|
d3cbc8ea78 | ||
|
|
b6e197371d | ||
|
|
5cc3ff16a3 | ||
|
|
d93d5d2e37 | ||
|
|
7491af8ad7 | ||
|
|
fce95431e6 | ||
|
|
591a07c0fe | ||
|
|
c410f2d151 | ||
|
|
9502fa62e6 | ||
|
|
2a6480ec48 | ||
|
|
7c5ab885be | ||
|
|
21cfb151a8 | ||
|
|
84505b1717 | ||
|
|
d735e3006e | ||
|
|
af5d82dbde | ||
|
|
a97072eca0 | ||
|
|
cef6e248e7 | ||
|
|
b4c379f5fc | ||
|
|
3bb1206b9c | ||
|
|
002532401d | ||
|
|
8957c5892f | ||
|
|
1b8f41d353 | ||
|
|
0c51cc3738 | ||
|
|
2b9a8f0822 | ||
|
|
ddcfff3b59 | ||
|
|
449a3959b0 | ||
|
|
719a0c485b | ||
|
|
a4bbdc443f | ||
|
|
999afdf05e | ||
|
|
f492f6deb6 | ||
|
|
60f7ec8998 | ||
|
|
469d0ade72 | ||
|
|
1f33b03c30 | ||
|
|
351be2f327 | ||
|
|
3f401e8cac | ||
|
|
b20b21c553 | ||
|
|
c62863b1dc | ||
|
|
8505a0f260 | ||
|
|
98d878cdfe | ||
|
|
6730731652 | ||
|
|
27c35f69aa | ||
|
|
53671283ae | ||
|
|
d9fc7b32c3 | ||
|
|
9a03536e3d | ||
|
|
efebb8bb0b | ||
|
|
3bd1ae0be4 | ||
|
|
a07291d904 | ||
|
|
c0ac457cad | ||
|
|
6813a31895 | ||
|
|
9d78ce6193 | ||
|
|
77bac11d82 | ||
|
|
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.
|
||||
|
||||
15
.github/workflows/main.yml
vendored
15
.github/workflows/main.yml
vendored
@@ -15,10 +15,10 @@ jobs:
|
||||
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
|
||||
@@ -31,6 +31,11 @@ jobs:
|
||||
run: platformio run -e heltec
|
||||
- name: Build for lora-relay-v1
|
||||
run: platformio run -e lora-relay-v1
|
||||
# Turn off linux for now
|
||||
#- 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,13 +4,7 @@ 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="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
|
||||
#BOARDS_ESP32=tbeam
|
||||
|
||||
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
|
||||
@@ -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
|
||||
|
||||
38
bin/build-nightly.sh
Executable file
38
bin/build-nightly.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
source ~/.bashrc
|
||||
|
||||
# Meshtastic Nightly Build Script.
|
||||
# McHamster (jm@casler.org)
|
||||
#
|
||||
# This is the script that is used for the nightly build server.
|
||||
#
|
||||
# It's probably not useful for most people, but you may want to run your own
|
||||
# nightly builds.
|
||||
#
|
||||
# The last line of ~/.bashrc contains an inclusion of platformio in the path.
|
||||
# Without this, the build script won't run from the crontab:
|
||||
#
|
||||
# export PATH="$HOME/.platformio/penv/bin:$PATH"
|
||||
#
|
||||
# The crontab contains:
|
||||
# 0 2 * * * cd ~/meshtastic/github/meshtastic && source "~/.bashrc"; ./build-nightly.sh > ~/cronout.txt 2> ~/cronout.txt
|
||||
|
||||
cd Meshtastic-device
|
||||
|
||||
git pull
|
||||
|
||||
bin/build-all.sh
|
||||
|
||||
date_stamp=$(date +'%Y-%m-%d')
|
||||
|
||||
cd ..
|
||||
|
||||
# TODO: Archive the same binaries used by the build-all script.
|
||||
#zip -r meshtastic_device_nightly_${date_stamp} Meshtastic-device/release/latest/bins
|
||||
cp Meshtastic-device/release/archive/`ls -t ./Meshtastic-device/release/archive/| head -1` meshtastic_device_nightly_${date_stamp}.zip
|
||||
|
||||
# Copy the file to the webserver
|
||||
scp meshtastic_device_nightly_${date_stamp}.zip jm@10.11.12.20:/volume1/web/meshtastic/nightly_builds/
|
||||
|
||||
# Delete the local copy
|
||||
rm meshtastic_device_nightly_${date_stamp}.zip
|
||||
@@ -1,21 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
PYTHON=${PYTHON:-python}
|
||||
|
||||
set -e
|
||||
|
||||
# Usage info
|
||||
show_help() {
|
||||
cat << EOF
|
||||
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-f FILENAME]
|
||||
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME]
|
||||
Flash image file to device, but first erasing and writing system information"
|
||||
|
||||
-h Display this help and exit
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
|
||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
while getopts ":h:p:f:" opt; do
|
||||
while getopts ":hp:P:f:" opt; do
|
||||
case "${opt}" in
|
||||
h)
|
||||
show_help
|
||||
@@ -23,6 +26,8 @@ while getopts ":h:p:f:" opt; do
|
||||
;;
|
||||
p) export ESPTOOL_PORT=${OPTARG}
|
||||
;;
|
||||
P) PYTHON=${OPTARG}
|
||||
;;
|
||||
f) FILENAME=${OPTARG}
|
||||
;;
|
||||
*)
|
||||
@@ -36,10 +41,10 @@ shift "$((OPTIND-1))"
|
||||
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
esptool.py --baud 921600 erase_flash
|
||||
esptool.py --baud 921600 write_flash 0x1000 system-info.bin
|
||||
esptool.py --baud 921600 write_flash 0x00390000 spiffs-*.bin
|
||||
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||
$PYTHON -m esptool --baud 921600 erase_flash
|
||||
$PYTHON -m esptool --baud 921600 write_flash 0x1000 system-info.bin
|
||||
$PYTHON -m esptool --baud 921600 write_flash 0x00390000 spiffs-*.bin
|
||||
$PYTHON -m esptool --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
PYTHON=${PYTHON:-python}
|
||||
|
||||
# Usage info
|
||||
show_help() {
|
||||
cat << EOF
|
||||
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] -f FILENAME
|
||||
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-P PYTHON] -f FILENAME
|
||||
Flash image file to device, leave existing system intact."
|
||||
|
||||
-h Display this help and exit
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
|
||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
while getopts ":h:p:f:" opt; do
|
||||
while getopts ":hp:P:f:" opt; do
|
||||
case "${opt}" in
|
||||
h)
|
||||
show_help
|
||||
@@ -21,6 +24,8 @@ while getopts ":h:p:f:" opt; do
|
||||
;;
|
||||
p) export ESPTOOL_PORT=${OPTARG}
|
||||
;;
|
||||
P) PYTHON=${OPTARG}
|
||||
;;
|
||||
f) FILENAME=${OPTARG}
|
||||
;;
|
||||
*)
|
||||
@@ -34,7 +39,9 @@ shift "$((OPTIND-1))"
|
||||
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash update ${FILENAME}."
|
||||
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||
$PYTHON -m esptool --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
|
||||
$PYTHON -m esptool --baud 921600 erase_region 0xe000 0x2000
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
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
|
||||
3
bin/program-1.0-tbeam.sh
Executable file
3
bin/program-1.0-tbeam.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-EU865-1.0.0.bin
|
||||
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
|
||||
esptool.py --baud 921600 erase_region 0xe000 0x2000
|
||||
1
bin/program-1.1-tbeam.sh
Executable file
1
bin/program-1.1-tbeam.sh
Executable file
@@ -0,0 +1 @@
|
||||
esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-1.1.50.bin
|
||||
11
bin/run-both.sh
Executable file
11
bin/run-both.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
set -e
|
||||
|
||||
pio run
|
||||
|
||||
echo uploading to usb1
|
||||
pio run --upload-port /dev/ttyUSB1 -t upload &
|
||||
|
||||
echo uploading to usb0
|
||||
pio run --upload-port /dev/ttyUSB0 -t upload &
|
||||
|
||||
wait
|
||||
48
boards/lora_isp4520.json
Normal file
48
boards/lora_isp4520.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52832_s132_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DNRF52832_XXAA -DNRF52",
|
||||
"f_cpu": "64000000L",
|
||||
"mcu": "nrf52832",
|
||||
"variant": "lora_isp4520",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS132",
|
||||
"sd_name": "s132",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B7"
|
||||
}
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth"
|
||||
],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52832_xxAA",
|
||||
"svd_path": "nrf52.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "lora ISP4520",
|
||||
"upload": {
|
||||
"maximum_ram_size": 65536,
|
||||
"maximum_size": 524288,
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"stlink"
|
||||
]
|
||||
},
|
||||
"url": "",
|
||||
"vendor": "PsiSoft"
|
||||
}
|
||||
@@ -2,11 +2,41 @@
|
||||
|
||||
You probably don't care about this section - skip to the next one.
|
||||
|
||||
## 1.2 cleanup & multichannel support:
|
||||
## before next release
|
||||
|
||||
* timestamps on oled screen are wrong - don't seem to be updating based on message rx
|
||||
* luxon bug report - seeing rx acks for nodes that are not on the network
|
||||
* channel hash suffixes are wrong on android
|
||||
* DONE test latest firmware update with is_router
|
||||
* DONE firmware OTA updates of is_router true nodes fails?
|
||||
* DONE add UI in android app to reset to defaults https://github.com/meshtastic/Meshtastic-Android/issues/263
|
||||
* DONE TEST THIS! changing channels requires a reboot to take effect https://github.com/meshtastic/Meshtastic-device/issues/752
|
||||
* DIBE bug report with remote info request timing out
|
||||
* DONE retest channel changing in android (using sim?)
|
||||
* DONE move remote admin doc from forum into git
|
||||
* DONE check crashlytics
|
||||
* DONE ask for a documentation czar
|
||||
* DONE timestamps on oled screen are wrong - don't seem to be updating based on message rx (actually: this is expected behavior when no node on the mesh has GPS time)
|
||||
* DONE add ch-del
|
||||
* DONE channel hash suffixes are wrong on android
|
||||
* DONE before next relase: test empty channel sets on android
|
||||
* DONE channel sharing in android
|
||||
* DONE test 1.0 firmware update on android
|
||||
* DONE test 1.1 firmware update on android
|
||||
* DONE test 1.2.10 firmware update on android
|
||||
* DONE test link sharing on android
|
||||
* FIXED? luxon bug report - seeing rx acks for nodes that are not on the network
|
||||
* DONE release py
|
||||
* DONE show GPS time only if we know what global time is
|
||||
* DONE android should always provide time to nodes - so that it is easier for the mesh to learn the current time
|
||||
|
||||
## MQTT
|
||||
|
||||
## Multichannel support
|
||||
|
||||
* DONE cleanup the external notification and serial plugins
|
||||
* non ack version of stress test fails sometimes!
|
||||
* tx fault test has a bug #734 - * turn off fault 8: https://github.com/meshtastic/Meshtastic-device/issues/734
|
||||
* DONE move device types into an enum in nodeinfo
|
||||
* DONE fix android to use new device types for firmware update
|
||||
* nrf52 should preserve local time across reset
|
||||
* cdcacm bug on nrf52: emittx thinks it emitted but client sees nothing. works again later
|
||||
* nrf52: segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger)
|
||||
* DONE call RouterPlugin for *all* packets - not just Router packets
|
||||
@@ -34,12 +64,11 @@ You probably don't care about this section - skip to the next one.
|
||||
* 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
|
||||
* DONE fix 1.1.50 android debug panel display
|
||||
* DONE test android channel setting
|
||||
* DONE release to users
|
||||
* DONE warn in android app about unset regions
|
||||
@@ -48,19 +77,20 @@ You probably don't care about this section - skip to the next one.
|
||||
* 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
|
||||
* DONE test remote info and remote settings changes
|
||||
* make python tests more exhaustive
|
||||
* pick default random admin key
|
||||
* DONE 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...
|
||||
* 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 single byte 'well known' channel names for admin, gpio, etc...
|
||||
* use presence of gpio channel to enable gpio ops, same for serial etc...
|
||||
* DONE restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
|
||||
* DONE add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
|
||||
* stress test multi channel
|
||||
* DONE investigate @mc-hamster report of heap corruption
|
||||
* DONE use set-user from android
|
||||
* untrusted users should not be allowed to provide bogus times (via position broadcasts) to the rest of the mesh. Invent a new lowest quality notion of UntrustedTime.
|
||||
* use portuino TCP connection to debug with python API
|
||||
* 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)
|
||||
@@ -72,18 +102,21 @@ You probably don't care about this section - skip to the next one.
|
||||
* allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead
|
||||
* DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key.
|
||||
* when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets
|
||||
* 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
|
||||
* DONE confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
|
||||
* DONE confirm we are still multi hop routing flood broadcasts
|
||||
* DONE confirm we are still doing resends on unicast reliable packets
|
||||
* add history to routed packets: https://meshtastic.discourse.group/t/packet-source-tracking/2764/2
|
||||
* add support for full DSR unicast delivery
|
||||
* DONE move acks into routing
|
||||
* DONE make all subpackets different versions of data
|
||||
* DONE move routing control into a data packet
|
||||
* have phoneapi done via plugin (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
|
||||
* use reference counting and dynamic sizing for meshpackets.
|
||||
* let multiple PhoneAPI endpoints work at once
|
||||
* allow multiple simultaneous bluetooth connections (create the bluetooth phoneapi instance dynamically based on client id)
|
||||
* DONE figure out how to add micro_delta to position, make it so that phone apps don't need to understand it?
|
||||
* only send battery updates a max of once a minute
|
||||
* add python channel selection for sending
|
||||
* DONE add python channel selection for sending
|
||||
* DONE record recevied channel in meshpacket
|
||||
* test remote settings operations (confirm it works 3 hops away)
|
||||
* DONE make a primaryChannel global and properly maintain it when the phone sends setChannel
|
||||
@@ -94,42 +127,6 @@ You probably don't care about this section - skip to the next one.
|
||||
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
|
||||
* current draw no good
|
||||
* DONE: fix backlight
|
||||
* DONE - USB is busted because of power enable mode?
|
||||
* test CPU voltage? something is bad with RAM (removing eink module does not help)
|
||||
* test that board leaves bootloader always
|
||||
* test USB - works in bootloader
|
||||
* test LEDs
|
||||
* Test BME280
|
||||
* test gps
|
||||
* check GPS fast locking
|
||||
* tested! dlora
|
||||
* test eink backlight
|
||||
* tested! eink
|
||||
* test buttons
|
||||
* test battery charging
|
||||
* test serial flash
|
||||
* send updated app and bootloader image
|
||||
* OHH BME280! THAT IS GREAT!
|
||||
* make new screen work, ask for datasheet
|
||||
* say I think you could ship this
|
||||
* leds seem busted
|
||||
* fix hw_model: "nrf52unknown"
|
||||
* use larger icon for meshtastic logo
|
||||
* send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6
|
||||
* send PR for bootloader
|
||||
* fix nrf52 time/date
|
||||
* send new master bin file
|
||||
* send email about low power mode problems
|
||||
* support new flash chip in appload, possibly use low power mode
|
||||
* swbug! stuck busy tx occurred!
|
||||
|
||||
For app cleanup:
|
||||
|
||||
* use structured logging to kep logs in ram. Also send logs as packets to api clients
|
||||
@@ -181,6 +178,44 @@ This should nicely help 'router' nodes do the right thing when long range, or if
|
||||
* turn on amazon reviews support
|
||||
* add a tablet layout (with map next to messages) in the android app
|
||||
|
||||
# Completed
|
||||
|
||||
## eink 1.0
|
||||
|
||||
* DONE check email of reported issues
|
||||
* DONE turn off vbus driving (in bootloader)
|
||||
* new battery level sensing
|
||||
* current draw no good
|
||||
* DONE: fix backlight
|
||||
* DONE - USB is busted because of power enable mode?
|
||||
* test CPU voltage? something is bad with RAM (removing eink module does not help)
|
||||
* test that board leaves bootloader always
|
||||
* test USB - works in bootloader
|
||||
* test LEDs
|
||||
* Test BME280
|
||||
* test gps
|
||||
* check GPS fast locking
|
||||
* tested! dlora
|
||||
* test eink backlight
|
||||
* tested! eink
|
||||
* test buttons
|
||||
* test battery charging
|
||||
* test serial flash
|
||||
* send updated app and bootloader image
|
||||
* OHH BME280! THAT IS GREAT!
|
||||
* make new screen work, ask for datasheet
|
||||
* say I think you could ship this
|
||||
* leds seem busted
|
||||
* fix hw_model: "nrf52unknown"
|
||||
* use larger icon for meshtastic logo
|
||||
* send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6
|
||||
* send PR for bootloader
|
||||
* fix nrf52 time/date
|
||||
* send new master bin file
|
||||
* send email about low power mode problems
|
||||
* support new flash chip in appload, possibly use low power mode
|
||||
* swbug! stuck busy tx occurred!
|
||||
|
||||
# Old docs to merge
|
||||
|
||||
MESH RADIO PROTOCOL
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
Hi.
|
||||
|
||||
If you've landed here that means your android application is too old for the running device firmware. Usually our updates are backwards compatible, but in this special circumstance it is not. Sorry.
|
||||
If you've landed here that means your android application is too old for the running device firmware. Usually our updates are backwards compatible, but about once a year we have a "major protocol update" which requires all apps and devices to update to keep working with that version. Version 1.2 in March 2021 was one of those updates.
|
||||
|
||||
Probably, what this means is that you installed the **alpha test** version of the firmware from github. We really love people helping with development by running the alpha test binaries. But if you aren't ready to sign up for that right now, please go back to [github](https://github.com/meshtastic/Meshtastic-device/releases) and install the latest **not alpha** 1.1.x firmware.
|
||||
|
||||
If you **do** intend to run the alpha test please [opt-in](https://play.google.com/apps/testing/com.geeksville.mesh) to receive the alpha test version of the android application.
|
||||
|
||||
If you are willing to be an alpha tester, please keep an eye on our forum where we post frequent release notes. We also will actively help you with any bugs you might encounter (along our shared journey of new feature goodness).
|
||||
|
||||
If you have problems/questions please post in our [forum](https://meshtastic.discourse.group) and some nice person will probably help.
|
||||
If you have problems/questions please post in our [forum](https://meshtastic.discourse.group) and some nice person will probably help.
|
||||
|
||||
17
docs/software/channels.md
Normal file
17
docs/software/channels.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Multiple channel support
|
||||
|
||||
Version 1.2 of the software adds support for "multiple (simultaneous) channels". The idea behind this feature is that a mesh can allow multiple users/groups to be share common mesh infrastructure. Even including routing messages for others when no one except that subgroup of users has the encryption keys for their private channel.
|
||||
|
||||
### What is the PRIMARY channel
|
||||
|
||||
The way this works is that each node keeps a list of channels it knows about. One of those channels (normally the first 1) is labelled as the "PRIMARY" channel. The primary channel is the **only** channel that is used to set radio parameters. i.e. this channel controls things like spread factor, coding rate, bandwidth etc... Indirectly this channel also is used to select the specific frequency that all members of this mesh are talking over.
|
||||
|
||||
This channel may or may not have a PSK (encryption). If you are providing mesh to 'the public' we recommend that you always leave this channel with its default psk. The default PSK is technically encrypted (and random users sniffing the ether would have to use meshtastic to decode it), but the key is included in the github source code and you should assume any 'attacker' would have it. But for a 'public' mesh you want this, because it allows anyone using meshtastic in your area to send packets through 'your' mesh.
|
||||
|
||||
Note: Older meshtastic applications that don't yet understand multi-channel support will only show the user this channel.
|
||||
|
||||
### How to use SECONDARY channels
|
||||
|
||||
Any channel you add after that PRIMARY channel is SECONDARY. Secondary channels are used only for encyryption and (in the case of some special applications) security. If you would like to have a private channel over a more public mesh, you probably want to create a SECONDARY channel. When sharing that URL with your private group you will share the "Complete URL". The complete URL includes your secondary channel (for encryption) and the primary channel (to provide radio/mesh access).
|
||||
|
||||
Secondary channels **must** have a PSK (encryption).
|
||||
@@ -63,6 +63,36 @@ Be sure to turn off either the plugin configured as a sender or the device where
|
||||
|
||||
Also be mindful of your space usage on the file system. It has protections from filling up the space but it's best to delete old range test results.
|
||||
|
||||
# Application Examples
|
||||
|
||||
## Google Integration
|
||||
|
||||
@jfirwin on our forum [meshtastic.discourse.org](https://meshtastic.discourse.group/t/new-plugin-rangetestplugin/2591/49?u=mc-hamster) shared how to integrate the resulting csv file with Google Products.
|
||||
|
||||
### Earth
|
||||
|
||||
Steps:
|
||||
|
||||
1. [Download](https://www.google.com/earth/versions/#download-pro) 1 and open Google Earth
|
||||
1. Select File > Import
|
||||
2. Select CSV
|
||||
3. Select Delimited, Comma
|
||||
4. Make sure the button that states “This dataset does not contain latitude/longitude information, but street addresses” is unchecked
|
||||
5. Select “rx lat” & “rx long” for the appropriate lat/lng fields
|
||||
6. Click finish
|
||||
2. When it prompts you to create a style template, click yes.
|
||||
1. Set the name field to whichever column you want to be displayed on the map (don’t worry about this too much, when you click on an icon, all the relavant data appears)
|
||||
2. select a color, icon, etc. and hit ok.
|
||||
|
||||
Your data will load onto the map, make sure to click the checkbox next to your dataset in the sidebar to view it.
|
||||
|
||||
### My Maps
|
||||
|
||||
You can use [My Maps](http://mymaps.google.com/). It takes CSVs and the whole interface is much easier to work with.
|
||||
|
||||
Google has instructions on how to do that [here](https://support.google.com/mymaps/answer/3024836?co=GENIE.Platform%3DDesktop&hl=en#zippy=%2Cstep-prepare-your-info%2Cstep-import-info-into-the-map).
|
||||
|
||||
You can style the ranges differently based on the values, so you can have the pins be darker the if the SNR or RSSI (if that gets added) is higher.
|
||||
|
||||
# Known Problems
|
||||
|
||||
|
||||
121
docs/software/remote-admin.md
Normal file
121
docs/software/remote-admin.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Remote node administration
|
||||
|
||||
This is the first documentation for how to use the [multiple channels](channels.md) feature to enable remote adminstration of meshtastic nodes. i.e. let you talk through the mesh to some far away node and change that nodes settings. This is an advanced feature that (currently) few users would need. Also, keep in mind it is possible (if you are not careful) to assign settings to that remote node that cause it to completely drop off of your mesh.
|
||||
|
||||
Btw: I promised to document how multi-channel is now used to secure remote GPIO/serial access. But probably best to debug these instructions first, so I'll wait on that. If you **do** need to use remote GPIO/serial now, just follow these instructions but name your new channel "gpio" or "serial".
|
||||
|
||||
## Creating the "admin" channel
|
||||
|
||||
Okay - now that we've summarized what multiple-channel support is, we can move on to using it to provide remote administrative access to a node.
|
||||
|
||||
By default, nodes will **only** respond to adminstrative commands via the local USB/bluetooth/TCP interface. This provides basic security to prevent unauthorized access. This is actually how 'normal' administration and settings changes work. The only difference for the remote case is that we are sending those commands over the mesh.
|
||||
|
||||
Before a node will allow remote admin access, it must find a channel
|
||||
```
|
||||
meshtastic --info
|
||||
Connected to radio
|
||||
...
|
||||
Channels:
|
||||
PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }
|
||||
|
||||
Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ
|
||||
```
|
||||
|
||||
So from this output you see that this node knows about only one channel and that its PSK is set to the default value.
|
||||
|
||||
But if you then add an admin channel (with "meshtastic --ch-add admin"). Note: the name is important it must be "admin" (sorry):
|
||||
|
||||
Your channels will now look like this:
|
||||
```
|
||||
meshtastic --ch-add admin
|
||||
Connected to radio
|
||||
Writing modified channels to device
|
||||
|
||||
meshtastic --info
|
||||
Connected to radio
|
||||
...
|
||||
Channels:
|
||||
PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }
|
||||
SECONDARY psk=secret { "psk": "HW7E3nMbiNbvr6MhsDonLCmj7eSAhttzjbIx/r5OQmg=", "name": "admin" }
|
||||
|
||||
Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ
|
||||
Complete URL (includes all channels): https://www.meshtastic.org/d/#CgUYAyIBAQopIiAdbsTecxuI1u-voyGwOicsKaPt5ICG23ONsjH-vk5CaCoFYWRtaW4
|
||||
```
|
||||
|
||||
Notice that now we have a new secondary channel. Also, the "--info" option prints out TWO URLs. The "complete URL" includes all of the channels this node understands. You should consider this URL something you should be very cautious about sharing. In the case of remote adminstration, you only need the node you want to adminster and the node you are locally connected to know this new "admin" channel.
|
||||
|
||||
## Sharing the admin channel with other nodes
|
||||
|
||||
I'm going to assume you've already created the admin channel on your "local node" i.e. the meshtastic node sitting on your desk at your home. But now you want to enable access on the "remote node" you want to eventually have far away from you.
|
||||
|
||||
For this step you need physical access to both the nodes.
|
||||
|
||||
1. Create the "admin" channel on the "local node" using the instructions above.
|
||||
2. Copy the "Complete URL" someplace for permanent reference/access.
|
||||
3. Connect meshtastic-python to the "remote node" over the USB port.
|
||||
4. For the "remote node" type "meshtastic --seturl the-url-from-step-2".
|
||||
5. Run "meshtastic --info" and confirm that the "Complete URL" is the same for both of the nodes.
|
||||
6. Done!
|
||||
|
||||
At this point you can take your remote node and install it far away and still be able to change any of its settings.
|
||||
|
||||
## Remotely administering your node
|
||||
|
||||
Now that both your local node and the remote node contain your secret admin channel key, you can do things like this:
|
||||
|
||||
Get the node list from the local node.
|
||||
|
||||
```
|
||||
meshtastic --nodes
|
||||
Connected to radio
|
||||
/----------------------------------------------------------------------------------------------------------\
|
||||
|N| User |AKA| ID | Position |Battery| SNR | LastHeard | Since |
|
||||
|-+------------+---+---------+------------------------+-------+---------+-------------------+--------------|
|
||||
|1|Unknown 9058|?58|!28979058|25.0382°, 121.5731°, N/A| N/A |-13.50 dB|2021-03-22 09:25:42|19 seconds ago|
|
||||
\----------------------------------------------------------------------------------------------------------/
|
||||
```
|
||||
|
||||
Using the node ID from that list, send a message through the mesh telling that node to change its owner name.
|
||||
|
||||
```
|
||||
meshtastic --dest \!28979058 --set-owner "Im Remote"
|
||||
Connected to radio
|
||||
Setting device owner to Im Remote
|
||||
INFO:root:Requesting configuration from remote node (this could take a while)
|
||||
```
|
||||
|
||||
And you can now confirm via the local node that the remote node has changed:
|
||||
|
||||
```
|
||||
meshtastic --nodes
|
||||
Connected to radio
|
||||
/----------------------------------------------------------------------------------------------------\
|
||||
|N| User |AKA| ID | Position |Battery| SNR | LastHeard | Since |
|
||||
|-+---------+---+---------+------------------------+-------+-------+-------------------+-------------|
|
||||
|1|Im Remote|IR |!28979058|25.0382°, 121.5731°, N/A| N/A |8.75 dB|2021-03-22 09:35:42|3 minutes ago|
|
||||
\----------------------------------------------------------------------------------------------------/
|
||||
```
|
||||
|
||||
Note: you can change **any** parameter, add channels or get info from the remote node. Here's an example of setting ls_secs and printing the complete device info from the remote node.
|
||||
|
||||
```
|
||||
meshtastic --dest \!28979058 --set ls_secs 301 --info
|
||||
Connected to radio
|
||||
INFO:root:Requesting configuration from remote node (this could take a while)
|
||||
Set ls_secs to 301
|
||||
Writing modified preferences to device
|
||||
|
||||
|
||||
Preferences: { "lsSecs": 301, "region": "TW" }
|
||||
|
||||
Channels:
|
||||
PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }
|
||||
SECONDARY psk=secret { "psk": "HW7E3nMbiNbvr6MhsDonLCmj7eSAhttzjbIx/r5OQmg=", "name": "admin" }
|
||||
|
||||
Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ
|
||||
Complete URL (includes all channels): https://www.meshtastic.org/d/#CgUYAyIBAQopIiAdbsTecxuI1u-voyGwOicsKaPt5ICG23ONsjH-vk5CaCoFYWRtaW4
|
||||
```
|
||||
|
||||
## Areas for future development
|
||||
|
||||
In the future we will add a "deadman timer" to this feature so that the remote node will revert any changes if you fail to send a special "commit changes" command. This will protect against sending bad settings to nodes that you can't physically access. Instead if the node does not receive a commit message within 10 minutes it will revert all changes and (hopefully) rejoin the mesh.
|
||||
@@ -6,5 +6,7 @@ This is a mini design doc for developing the meshtastic software.
|
||||
* Our [project board](https://github.com/orgs/meshtastic/projects/1) - shows what things we are currently working on and remaining work items for the current release.
|
||||
* [Power Management](power.md)
|
||||
* [Mesh algorithm](mesh-alg.md)
|
||||
* [Channels](channels.md) - documentation on how multiple simultaneous channels are used
|
||||
* [Remote adminstration](remote-admin.md)
|
||||
* [External client API](device-api.md) and porting guide for new clients (iOS, python, etc...)
|
||||
* TODO: how to port the device code to a new device.
|
||||
|
||||
@@ -13,11 +13,12 @@ default_envs = tbeam
|
||||
;default_envs = tbeam0.7
|
||||
;default_envs = heltec
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora_v1_3
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = lora-relay-v1 # nrf board
|
||||
;default_envs = eink
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;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 = 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
|
||||
@@ -39,7 +40,7 @@ extra_scripts = bin/platformio-custom.py
|
||||
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
|
||||
build_flags = -Wno-missing-field-initializers
|
||||
-Wno-format
|
||||
-Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map
|
||||
-Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||
-DHW_VERSION_${sysenv.COUNTRY}
|
||||
-DHW_VERSION=${sysenv.HW_VERSION}
|
||||
-DUSE_THREAD_NAMES
|
||||
@@ -158,6 +159,12 @@ build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V1
|
||||
|
||||
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
|
||||
[env:tlora_v1_3]
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V1_3
|
||||
|
||||
[env:tlora-v2]
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
@@ -232,6 +239,24 @@ debug_init_break =
|
||||
;debug_init_break = tbreak loop
|
||||
;debug_init_break = tbreak Reset_Handler
|
||||
|
||||
[env:lora_isp4520]
|
||||
extends = nrf52_base
|
||||
board = lora_isp4520
|
||||
|
||||
# add our variants files to the include and src paths
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_isp4520
|
||||
|
||||
# No screen and GPS on the board. We still need RTC.cpp for the RTC clock.
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/lora_isp4520> -<graphics> -<gps> +<gps/GPS.cpp> +<gps/RTC.cpp>
|
||||
lib_ignore = ${nrf52_base.lib_ignore}
|
||||
ESP8266_SSD1306
|
||||
SparkFun Ublox Arduino Library
|
||||
AXP202X_Library
|
||||
TinyGPSPlus
|
||||
|
||||
upload_protocol = jlink
|
||||
monitor_port = /dev/ttyUSB0
|
||||
|
||||
; The NRF52840-dk development board
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:nrf52840dk]
|
||||
@@ -355,19 +380,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: bf8ac6718c...820fa497df
@@ -5,12 +5,35 @@
|
||||
#include "sleep.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef TBEAM_V10
|
||||
// FIXME. nasty hack cleanup how we load axp192
|
||||
#undef AXP192_SLAVE_ADDRESS
|
||||
#include "axp20x.h"
|
||||
|
||||
#ifdef TBEAM_V10
|
||||
AXP20X_Class axp;
|
||||
#else
|
||||
// Copy of the base class defined in axp20x.h.
|
||||
// I'd rather not inlude axp20x.h as it brings Wire dependency.
|
||||
class HasBatteryLevel {
|
||||
public:
|
||||
/**
|
||||
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||
*/
|
||||
virtual int getBattPercentage() { return -1; }
|
||||
|
||||
/**
|
||||
* The raw voltage of the battery or NAN if unknown
|
||||
*/
|
||||
virtual float getBattVoltage() { return NAN; }
|
||||
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() { return false; }
|
||||
|
||||
virtual bool isVBUSPlug() { return false; }
|
||||
virtual bool isChargeing() { return false; }
|
||||
};
|
||||
#endif
|
||||
|
||||
bool pmu_irq = false;
|
||||
@@ -51,7 +74,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
*/
|
||||
virtual int getBattPercentage()
|
||||
{
|
||||
float v = getBattVoltage() / 1000;
|
||||
float v = getBattVoltage();
|
||||
|
||||
if (v < noBatVolt)
|
||||
return -1; // If voltage is super low assume no battery installed
|
||||
@@ -67,13 +90,26 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
*/
|
||||
virtual float getBattVoltage()
|
||||
{
|
||||
// Tested ttgo eink nrf52 board and the reported value is perfect
|
||||
// DEBUG_MSG("raw val %u", raw);
|
||||
return
|
||||
|
||||
#ifndef ADC_MULTIPLIER
|
||||
#define ADC_MULTIPLIER 2.0
|
||||
#endif
|
||||
|
||||
#ifdef BATTERY_PIN
|
||||
1000.0 * 2.0 * (AREF_VOLTAGE / 1024.0) * analogRead(BATTERY_PIN);
|
||||
// Do not call analogRead() often.
|
||||
const uint32_t min_read_interval = 5000;
|
||||
if (millis() - last_read_time_ms > min_read_interval) {
|
||||
last_read_time_ms = millis();
|
||||
uint32_t raw = analogRead(BATTERY_PIN);
|
||||
float scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
|
||||
// DEBUG_MSG("raw val=%u scaled=%u\n", raw, (uint32_t)(scaled));
|
||||
last_read_value = scaled;
|
||||
return scaled;
|
||||
} else {
|
||||
return last_read_value;
|
||||
}
|
||||
#else
|
||||
NAN;
|
||||
return NAN;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -93,7 +129,9 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
private:
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
const float fullVolt = 4.2, emptyVolt = 3.27, chargingVolt = 4.3, noBatVolt = 2.1;
|
||||
const float fullVolt = 4200, emptyVolt = 3270, chargingVolt = 4210, noBatVolt = 2100;
|
||||
float last_read_value = 0.0;
|
||||
uint32_t last_read_time_ms = 0;
|
||||
} analogLevel;
|
||||
|
||||
Power::Power() : OSThread("Power") {}
|
||||
@@ -140,6 +178,8 @@ void Power::shutdown()
|
||||
#ifdef TBEAM_V10
|
||||
DEBUG_MSG("Shutting down\n");
|
||||
axp.shutdown();
|
||||
#elif NRF52_SERIES
|
||||
doDeepSleep(DELAY_FOREVER);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,8 @@ static void lsIdle()
|
||||
static void lsExit()
|
||||
{
|
||||
// setGPSPower(true); // restore GPS power
|
||||
gps->forceWake(true);
|
||||
if (gps)
|
||||
gps->forceWake(true);
|
||||
}
|
||||
|
||||
static void nbEnter()
|
||||
@@ -172,7 +173,7 @@ Fsm powerFSM(&stateBOOT);
|
||||
void PowerFSM_setup()
|
||||
{
|
||||
bool isRouter = radioConfig.preferences.is_router;
|
||||
|
||||
|
||||
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
|
||||
// We assume routers might be powered all the time, but from a low current (solar) source
|
||||
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
|
||||
@@ -180,7 +181,7 @@ void PowerFSM_setup()
|
||||
/* To determine if we're externally powered, assumptions
|
||||
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
|
||||
|
||||
2) If we detect USB power from the power management chip, we must be getting power externally.
|
||||
2) If we detect USB power from the power management chip, we must be getting power externally.
|
||||
*/
|
||||
bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||
|
||||
@@ -249,6 +250,11 @@ void PowerFSM_setup()
|
||||
|
||||
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
||||
|
||||
// each time we get a new update packet make sure we are staying in the ON state so the screen stays awake (also we don't
|
||||
// shutdown bluetooth if is_router)
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||
|
||||
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
|
||||
|
||||
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define EVENT_SERIAL_DISCONNECTED 12
|
||||
#define EVENT_POWER_CONNECTED 13
|
||||
#define EVENT_POWER_DISCONNECTED 14
|
||||
#define EVENT_FIRMWARE_UPDATE 15 // We just received a new firmware update packet from the phone
|
||||
|
||||
extern Fsm powerFSM;
|
||||
extern State statePOWER, stateSERIAL;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "RedirectablePrint.h"
|
||||
#include "RTC.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
@@ -24,7 +25,8 @@ size_t RedirectablePrint::write(uint8_t c)
|
||||
#endif
|
||||
|
||||
dest->write(c);
|
||||
return 1; // We always claim one was written, rather than trusting what the serial port said (which could be zero)
|
||||
return 1; // We always claim one was written, rather than trusting what the
|
||||
// serial port said (which could be zero)
|
||||
}
|
||||
|
||||
size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
@@ -38,7 +40,7 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
va_end(arg);
|
||||
return 0;
|
||||
};
|
||||
if (len >= (int)printBufLen) {
|
||||
if (len >= printBufLen) {
|
||||
delete[] printBuf;
|
||||
printBufLen *= 2;
|
||||
printBuf = new char[printBufLen];
|
||||
@@ -49,10 +51,6 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
return len;
|
||||
}
|
||||
|
||||
#define SEC_PER_DAY 86400
|
||||
#define SEC_PER_HOUR 3600
|
||||
#define SEC_PER_MIN 60
|
||||
|
||||
size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
{
|
||||
size_t r = 0;
|
||||
@@ -68,9 +66,9 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
|
||||
// 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;
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
|
||||
if (rtc_sec > 0) {
|
||||
long hms = rtc_sec % SEC_PER_DAY;
|
||||
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||||
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
|
||||
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
|
||||
|
||||
@@ -47,8 +47,7 @@ class AirTime : private concurrency::OSThread
|
||||
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
|
||||
|
||||
protected:
|
||||
|
||||
virtual int32_t runOnce();
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern AirTime *airTime;
|
||||
66
src/buzz/buzz.cpp
Normal file
66
src/buzz/buzz.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "buzz.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef NRF52_SERIES
|
||||
#include "variant.h"
|
||||
#endif
|
||||
|
||||
#ifndef PIN_BUZZER
|
||||
|
||||
// Noop methods for boards w/o buzzer
|
||||
void playBeep(){};
|
||||
void playStartMelody(){};
|
||||
void playShutdownMelody(){};
|
||||
|
||||
#else
|
||||
#include "Tone.h"
|
||||
|
||||
extern "C" void delay(uint32_t dwMs);
|
||||
|
||||
struct ToneDuration {
|
||||
int frequency_khz;
|
||||
int duration_ms;
|
||||
};
|
||||
|
||||
// Some common frequencies.
|
||||
#define NOTE_C3 131
|
||||
#define NOTE_CS3 139
|
||||
#define NOTE_D3 147
|
||||
#define NOTE_DS3 156
|
||||
#define NOTE_E3 165
|
||||
#define NOTE_F3 175
|
||||
#define NOTE_FS3 185
|
||||
#define NOTE_G3 196
|
||||
#define NOTE_GS3 208
|
||||
#define NOTE_A3 220
|
||||
#define NOTE_AS3 233
|
||||
#define NOTE_B3 247
|
||||
|
||||
const int DURATION_1_8 = 125; // 1/8 note
|
||||
const int DURATION_1_4 = 250; // 1/4 note
|
||||
|
||||
void playTones(const ToneDuration *tone_durations, int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
const auto &tone_duration = tone_durations[i];
|
||||
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||
// to distinguish the notes, set a minimum time between them.
|
||||
delay(1.3 * tone_duration.duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
|
||||
|
||||
void playStartMelody() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||
{NOTE_B3, DURATION_1_8},
|
||||
{NOTE_B3, DURATION_1_8}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
void playShutdownMelody() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||
{NOTE_G3, DURATION_1_8},
|
||||
{NOTE_D3, DURATION_1_8}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#endif
|
||||
5
src/buzz/buzz.h
Normal file
5
src/buzz/buzz.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void playBeep();
|
||||
void playStartMelody();
|
||||
void playShutdownMelody();
|
||||
@@ -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_V1_1p3
|
||||
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
@@ -338,11 +338,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(TLORA_V2_1_16)
|
||||
// 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
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_RX_PIN 15 // per @der_bear on the forum, 36 is incorrect for this board type and 15 is a better pick
|
||||
#define GPS_TX_PIN 13
|
||||
|
||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
@@ -366,7 +366,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#elif defined(GENIEBLOCKS)
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "../concurrency/LockGuard.h"
|
||||
#include "../graphics/Screen.h"
|
||||
#include "../main.h"
|
||||
#include "BluetoothSoftwareUpdate.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "configuration.h"
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#include "NodeDB.h"
|
||||
#include "../graphics/Screen.h"
|
||||
#include "../main.h"
|
||||
|
||||
#include <CRC32.h>
|
||||
#include <Update.h>
|
||||
@@ -51,8 +51,8 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
|
||||
|
||||
screen->startFirmwareUpdateScreen();
|
||||
if (RadioLibInterface::instance)
|
||||
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are
|
||||
// writing flash - shut the radio off during updates
|
||||
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we
|
||||
// are writing flash - shut the radio off during updates
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
|
||||
crc.update(data, len);
|
||||
Update.write(data, len);
|
||||
updateActualSize += len;
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
||||
powerFSM.trigger(EVENT_FIRMWARE_UPDATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -107,8 +107,7 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble
|
||||
if (update_region == U_SPIFFS) {
|
||||
DEBUG_MSG("SPIFFS updated!\n");
|
||||
nodeDB.saveToDisk(); // Since we just wiped spiffs, we need to save our current state
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
|
||||
@@ -308,3 +308,49 @@ int GPS::prepareDeepSleep(void *unused)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef GPS_TX_PIN
|
||||
#include "UBloxGPS.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_AIR530_GPS
|
||||
#include "Air530GPS.h"
|
||||
#elif !defined(NO_GPS)
|
||||
#include "NMEAGPS.h"
|
||||
#endif
|
||||
|
||||
|
||||
GPS* createGps() {
|
||||
|
||||
#ifdef NO_GPS
|
||||
return nullptr;
|
||||
#else
|
||||
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
||||
#ifdef GPS_TX_PIN
|
||||
// Init GPS - first try ublox
|
||||
UBloxGPS *ublox = new UBloxGPS();
|
||||
|
||||
if (!ublox->setup()) {
|
||||
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
||||
delete ublox;
|
||||
ublox = NULL;
|
||||
} else {
|
||||
return ublox;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (GPS::_serial_gps) {
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||
// assume NMEA at 9600 baud.
|
||||
DEBUG_MSG("Hoping that NMEA might work\n");
|
||||
#ifdef HAS_AIR530_GPS
|
||||
GPS* new_gps = new Air530GPS();
|
||||
#else
|
||||
GPS* new_gps = new NMEAGPS();
|
||||
#endif
|
||||
new_gps->setup();
|
||||
return new_gps;
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
@@ -71,6 +71,9 @@ class GPS : private concurrency::OSThread
|
||||
* */
|
||||
void forceWake(bool on);
|
||||
|
||||
// Some GPS modules (ublock) require factory reset
|
||||
virtual bool factoryReset() { return true; }
|
||||
|
||||
protected:
|
||||
/// Do gps chipset specific init, return true for success
|
||||
virtual bool setupGPS();
|
||||
@@ -145,4 +148,8 @@ class GPS : private concurrency::OSThread
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
// Creates an instance of the GPS class.
|
||||
// Returns the new instance or null if the GPS is not present.
|
||||
GPS* createGps();
|
||||
|
||||
extern GPS *gps;
|
||||
|
||||
@@ -42,19 +42,20 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) {
|
||||
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
|
||||
shouldSet = true;
|
||||
DEBUG_MSG("Reapplying GPS time to correct clock drift %ld secs\n", tv->tv_sec);
|
||||
DEBUG_MSG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
|
||||
}
|
||||
else
|
||||
shouldSet = false;
|
||||
|
||||
if (shouldSet) {
|
||||
lastSetMsec = now;
|
||||
lastSetMsec = now;
|
||||
#ifndef NO_ESP32
|
||||
settimeofday(tv, NULL);
|
||||
#else
|
||||
DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n");
|
||||
#endif
|
||||
readFromRTC();
|
||||
#else
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv->tv_sec;
|
||||
#endif
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -27,4 +27,8 @@ uint32_t getTime();
|
||||
/// Return time since 1970 in secs. If quality is RTCQualityNone return zero
|
||||
uint32_t getValidTime(RTCQuality minQuality);
|
||||
|
||||
void readFromRTC();
|
||||
void readFromRTC();
|
||||
|
||||
#define SEC_PER_DAY 86400
|
||||
#define SEC_PER_HOUR 3600
|
||||
#define SEC_PER_MIN 60
|
||||
@@ -28,11 +28,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "Screen.h"
|
||||
#include "configuration.h"
|
||||
#include "fonts.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
#include "mesh/Channels.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
|
||||
@@ -155,24 +156,22 @@ static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
||||
{
|
||||
uint8_t plugin_frame;
|
||||
// there's a little but in the UI transition code
|
||||
// where it invokes the function at the correct offset
|
||||
// where it invokes the function at the correct offset
|
||||
// in the array of "drawScreen" functions; however,
|
||||
// the passed-state doesn't quite reflect the "current"
|
||||
// the passed-state doesn't quite reflect the "current"
|
||||
// screen, so we have to detect it.
|
||||
if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) {
|
||||
// if we're transitioning from the end of the frame list back around to the first
|
||||
// if we're transitioning from the end of the frame list back around to the first
|
||||
// frame, then we want this to be `0`
|
||||
plugin_frame = state->transitionFrameTarget;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// otherwise, just display the plugin frame that's aligned with the current frame
|
||||
plugin_frame = state->currentFrame;
|
||||
//DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
|
||||
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
|
||||
}
|
||||
//DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
|
||||
// DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
|
||||
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
|
||||
pi.drawFrame(display,state,x,y);
|
||||
|
||||
pi.drawFrame(display, state, x, y);
|
||||
}
|
||||
|
||||
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@@ -204,11 +203,10 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait...");
|
||||
|
||||
//display->setFont(FONT_LARGE);
|
||||
//display->drawString(64 + x, 26 + y, btPIN);
|
||||
// display->setFont(FONT_LARGE);
|
||||
// display->drawString(64 + x, 26 + y, btPIN);
|
||||
}
|
||||
|
||||
|
||||
/// Draw the last text message we received
|
||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -793,7 +791,7 @@ void Screen::setup()
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
if(textMessagePlugin)
|
||||
if (textMessagePlugin)
|
||||
textMessageObserver.observe(textMessagePlugin);
|
||||
}
|
||||
|
||||
@@ -842,7 +840,7 @@ int32_t Screen::runOnce()
|
||||
break;
|
||||
case Cmd::START_FIRMWARE_UPDATE_SCREEN:
|
||||
handleStartFirmwareUpdateScreen();
|
||||
break;
|
||||
break;
|
||||
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
|
||||
case Cmd::STOP_BOOT_SCREEN:
|
||||
setFrames();
|
||||
@@ -936,7 +934,7 @@ void Screen::setFrames()
|
||||
for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) {
|
||||
normalFrames[numframes++] = drawPluginFrame;
|
||||
}
|
||||
|
||||
|
||||
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
|
||||
|
||||
// If we have a critical fault, show it first
|
||||
@@ -1286,14 +1284,41 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
uint32_t minutes = seconds / 60;
|
||||
uint32_t hours = minutes / 60;
|
||||
uint32_t days = hours / 24;
|
||||
currentMillis %= 1000;
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 24;
|
||||
// currentMillis %= 1000;
|
||||
// seconds %= 60;
|
||||
// minutes %= 60;
|
||||
// hours %= 24;
|
||||
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
|
||||
String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
|
||||
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
|
||||
// Show uptime as days, hours, minutes OR seconds
|
||||
String uptime;
|
||||
if (days >= 2)
|
||||
uptime += String(days) + "d ";
|
||||
else if (hours >= 2)
|
||||
uptime += String(hours) + "h ";
|
||||
else if (minutes >= 1)
|
||||
uptime += String(minutes) + "m ";
|
||||
else
|
||||
uptime += String(seconds) + "s ";
|
||||
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
|
||||
if (rtc_sec > 0) {
|
||||
long hms = rtc_sec % SEC_PER_DAY;
|
||||
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||||
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
|
||||
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
|
||||
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||||
|
||||
// Tear apart hms into h:m:s
|
||||
int hour = hms / SEC_PER_HOUR;
|
||||
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||||
|
||||
char timebuf[9];
|
||||
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", hour, min, sec);
|
||||
uptime += timebuf;
|
||||
}
|
||||
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, uptime);
|
||||
|
||||
#ifndef NO_ESP32
|
||||
// Show CPU Frequency.
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NO_SCREEN
|
||||
namespace graphics
|
||||
{
|
||||
// Noop class for boards without screen.
|
||||
class Screen
|
||||
{
|
||||
public:
|
||||
Screen(char){}
|
||||
void onPress() {}
|
||||
void setup() {}
|
||||
void setOn(bool) {}
|
||||
void print(const char*){}
|
||||
void adjustBrightness(){}
|
||||
void doDeepSleep() {}
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
#include <cstring>
|
||||
|
||||
#include <OLEDDisplayUi.h>
|
||||
@@ -278,3 +296,4 @@ class Screen : public concurrency::OSThread
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
78
src/main.cpp
78
src/main.cpp
@@ -1,11 +1,11 @@
|
||||
|
||||
#include "Air530GPS.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "UBloxGPS.h"
|
||||
#include "airtime.h"
|
||||
#include "buzz.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "power.h"
|
||||
@@ -32,6 +32,10 @@
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#endif
|
||||
|
||||
#ifdef PORTDUINO
|
||||
#include "mesh/wifi/WiFiServerAPI.h"
|
||||
#endif
|
||||
|
||||
#include "RF95Interface.h"
|
||||
#include "SX1262Interface.h"
|
||||
|
||||
@@ -63,7 +67,7 @@ Router *router = NULL; // Users of router don't care what sort of subclass imple
|
||||
// -----------------------------------------------------------------------------
|
||||
// Application
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#ifndef NO_WIRE
|
||||
void scanI2Cdevice(void)
|
||||
{
|
||||
byte err, addr;
|
||||
@@ -100,6 +104,9 @@ void scanI2Cdevice(void)
|
||||
else
|
||||
DEBUG_MSG("done\n");
|
||||
}
|
||||
#else
|
||||
void scanI2Cdevice(void) {}
|
||||
#endif
|
||||
|
||||
const char *getDeviceName()
|
||||
{
|
||||
@@ -169,7 +176,7 @@ class ButtonThread : public OSThread
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
OneButton userButtonAlt;
|
||||
#endif
|
||||
|
||||
static bool shutdown_on_long_stop;
|
||||
public:
|
||||
static uint32_t longPressTime;
|
||||
|
||||
@@ -235,13 +242,23 @@ class ButtonThread : public OSThread
|
||||
// DEBUG_MSG("Long press!\n");
|
||||
screen->adjustBrightness();
|
||||
|
||||
// If user button is held down for 10 seconds, shutdown the device.
|
||||
if (millis() - longPressTime > 10 * 1000) {
|
||||
// If user button is held down for 5 seconds, shutdown the device.
|
||||
if (millis() - longPressTime > 5 * 1000) {
|
||||
#ifdef TBEAM_V10
|
||||
if (axp192_found == true) {
|
||||
setLed(false);
|
||||
power->shutdown();
|
||||
}
|
||||
#elif NRF52_SERIES
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
if (!shutdown_on_long_stop) {
|
||||
DEBUG_MSG("Shutdown from long press");
|
||||
playBeep();
|
||||
ledOff(PIN_LED1);
|
||||
ledOff(PIN_LED2);
|
||||
shutdown_on_long_stop = true;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
|
||||
@@ -265,9 +282,15 @@ class ButtonThread : public OSThread
|
||||
{
|
||||
DEBUG_MSG("Long press stop!\n");
|
||||
longPressTime = 0;
|
||||
if (shutdown_on_long_stop) {
|
||||
playShutdownMelody();
|
||||
power->shutdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool ButtonThread::shutdown_on_long_stop = false;
|
||||
|
||||
static Periodic *ledPeriodic;
|
||||
static OSThread *powerFSMthread, *buttonThread;
|
||||
uint32_t ButtonThread::longPressTime = 0;
|
||||
@@ -341,7 +364,7 @@ void setup()
|
||||
|
||||
#ifdef I2C_SDA
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
#else
|
||||
#elif !defined(NO_WIRE)
|
||||
Wire.begin();
|
||||
#endif
|
||||
|
||||
@@ -365,7 +388,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
|
||||
@@ -378,7 +401,7 @@ void setup()
|
||||
#ifdef NRF52_SERIES
|
||||
nrf52Setup();
|
||||
#endif
|
||||
|
||||
playStartMelody();
|
||||
// We do this as early as possible because this loads preferences from flash
|
||||
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
|
||||
nodeDB.init();
|
||||
@@ -416,34 +439,7 @@ void setup()
|
||||
pinMode(BATTERY_EN_PIN, OUTPUT);
|
||||
digitalWrite(BATTERY_EN_PIN, LOW);
|
||||
#endif
|
||||
|
||||
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
||||
UBloxGPS *ublox = NULL;
|
||||
#ifdef GPS_TX_PIN
|
||||
// Init GPS - first try ublox
|
||||
ublox = new UBloxGPS();
|
||||
gps = ublox;
|
||||
if (!gps->setup()) {
|
||||
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
||||
|
||||
delete ublox;
|
||||
gps = ublox = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!gps && GPS::_serial_gps) {
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||
// assume NMEA at 9600 baud.
|
||||
// dumb NMEA access only work for serial GPSes)
|
||||
DEBUG_MSG("Hoping that NMEA might work\n");
|
||||
|
||||
#ifdef HAS_AIR530_GPS
|
||||
gps = new Air530GPS();
|
||||
#else
|
||||
gps = new NMEAGPS();
|
||||
#endif
|
||||
gps->setup();
|
||||
}
|
||||
gps = createGps();
|
||||
|
||||
if (gps)
|
||||
gpsStatus->observe(&gps->newStatus);
|
||||
@@ -477,8 +473,8 @@ void setup()
|
||||
// We have now loaded our saved preferences from flash
|
||||
|
||||
// ONCE we will factory reset the GPS for bug #327
|
||||
if (ublox && !devicestate.did_gps_reset) {
|
||||
if (ublox->factoryReset()) { // If we don't succeed try again next time
|
||||
if (gps && !devicestate.did_gps_reset) {
|
||||
if (gps->factoryReset()) { // If we don't succeed try again next time
|
||||
devicestate.did_gps_reset = true;
|
||||
nodeDB.saveToDisk();
|
||||
}
|
||||
@@ -539,6 +535,10 @@ void setup()
|
||||
webServerThread = new WebServerThread();
|
||||
#endif
|
||||
|
||||
#ifdef PORTDUINO
|
||||
initApiServer();
|
||||
#endif
|
||||
|
||||
// Start airtime logger thread.
|
||||
airTime = new AirTime();
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ 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;
|
||||
@@ -29,7 +33,7 @@ int16_t Channels::generateHash(ChannelIndex channelNum)
|
||||
return -1; // invalid
|
||||
else {
|
||||
const char *name = getName(channelNum);
|
||||
uint8_t h = xorHash((const uint8_t *) name, strlen(name));
|
||||
uint8_t h = xorHash((const uint8_t *)name, strlen(name));
|
||||
|
||||
h ^= xorHash(k.bytes, k.length);
|
||||
|
||||
@@ -180,7 +184,7 @@ void Channels::onConfigChanged()
|
||||
|
||||
Channel &Channels::getByIndex(ChannelIndex chIndex)
|
||||
{
|
||||
assert(chIndex < channelFile.channels_count);
|
||||
assert(chIndex < channelFile.channels_count); // This should be equal to MAX_NUM_CHANNELS
|
||||
Channel *ch = channelFile.channels + chIndex;
|
||||
return *ch;
|
||||
}
|
||||
@@ -274,11 +278,11 @@ const char *Channels::getPrimaryName()
|
||||
*/
|
||||
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
|
||||
{
|
||||
if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
|
||||
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex), channelHash);
|
||||
if (chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
|
||||
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex),
|
||||
// channelHash);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} 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 */
|
||||
|
||||
@@ -31,6 +31,39 @@ MeshPlugin::~MeshPlugin()
|
||||
assert(0); // FIXME - remove from list of plugins once someone needs this feature
|
||||
}
|
||||
|
||||
MeshPacket *MeshPlugin::allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
{
|
||||
Routing c = Routing_init_default;
|
||||
|
||||
c.error_reason = err;
|
||||
|
||||
// Now that we have moded sendAckNak up one level into the class heirarchy we can no longer assume we are a RoutingPlugin
|
||||
// So we manually call pb_encode_to_bytes and specify routing port number
|
||||
// auto p = allocDataProtobuf(c);
|
||||
MeshPacket *p = router->allocForSending();
|
||||
p->decoded.portnum = PortNum_ROUTING_APP;
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Routing_fields, &c);
|
||||
|
||||
p->priority = MeshPacket_Priority_ACK;
|
||||
|
||||
p->hop_limit = 0; // Assume just immediate neighbors for now
|
||||
p->to = to;
|
||||
p->decoded.request_id = idFrom;
|
||||
p->channel = chIndex;
|
||||
DEBUG_MSG("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
MeshPacket *MeshPlugin::allocErrorResponse(Routing_Error err, const MeshPacket *p)
|
||||
{
|
||||
auto r = allocAckNak(err, getFrom(p), p->id, p->channel);
|
||||
|
||||
setReplyTo(r, *p);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
{
|
||||
// DEBUG_MSG("In call plugins\n");
|
||||
@@ -52,33 +85,47 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
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);
|
||||
bool wantsPacket = (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||
|
||||
if (wantsPacket) {
|
||||
// DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
pluginFound = true;
|
||||
|
||||
bool handled = pi.handleReceived(mp);
|
||||
/// Is the channel this packet arrived on acceptable? (security check)
|
||||
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0);
|
||||
|
||||
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing)
|
||||
// also: we only let the one plugin send a reply, once that happens, remaining plugins are not considered
|
||||
if (!rxChannelOk) {
|
||||
// no one should have already replied!
|
||||
assert(!currentReply);
|
||||
|
||||
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because
|
||||
// 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);
|
||||
if (mp.decoded.want_response) {
|
||||
DEBUG_MSG("packet on wrong channel, returning error\n");
|
||||
currentReply = pi.allocErrorResponse(Routing_Error_NOT_AUTHORIZED, &mp);
|
||||
} else
|
||||
DEBUG_MSG("packet on wrong channel, but client didn't want response\n");
|
||||
} else {
|
||||
DEBUG_MSG("Plugin %s considered\n", pi.name);
|
||||
}
|
||||
if (handled) {
|
||||
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
|
||||
break;
|
||||
|
||||
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 && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
|
||||
pi.sendResponse(mp);
|
||||
DEBUG_MSG("Plugin %s sent a response\n", pi.name);
|
||||
} else {
|
||||
DEBUG_MSG("Plugin %s considered\n", pi.name);
|
||||
}
|
||||
if (handled) {
|
||||
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +137,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
DEBUG_MSG("Sending response\n");
|
||||
service.sendToMesh(currentReply);
|
||||
currentReply = NULL;
|
||||
}
|
||||
else {
|
||||
} 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);
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "mesh/Channels.h"
|
||||
#include "mesh/MeshTypes.h"
|
||||
#include <vector>
|
||||
|
||||
#ifndef NO_SCREEN
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
/** A baseclass for any mesh "plugin".
|
||||
*
|
||||
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||
@@ -31,9 +36,9 @@ class MeshPlugin
|
||||
static void callPlugins(const MeshPacket &mp);
|
||||
|
||||
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
|
||||
|
||||
#ifndef NO_SCREEN
|
||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
|
||||
|
||||
#endif
|
||||
protected:
|
||||
const char *name;
|
||||
|
||||
@@ -86,6 +91,11 @@ class MeshPlugin
|
||||
*/
|
||||
virtual bool wantUIFrame() { return false; }
|
||||
|
||||
MeshPacket *allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
|
||||
|
||||
/// Send an error response for the specified packet.
|
||||
MeshPacket *allocErrorResponse(Routing_Error err, const MeshPacket *p);
|
||||
|
||||
private:
|
||||
/**
|
||||
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
|
||||
|
||||
@@ -82,16 +82,17 @@ bool NodeDB::resetRadioConfig()
|
||||
|
||||
radioGeneration++;
|
||||
|
||||
radioConfig.has_preferences = true;
|
||||
if (radioConfig.preferences.factory_reset) {
|
||||
DEBUG_MSG("Performing factory reset!\n");
|
||||
installDefaultDeviceState();
|
||||
didFactoryReset = true;
|
||||
} else if (channelFile.channels_count == 0) {
|
||||
}
|
||||
|
||||
if (channelFile.channels_count != MAX_NUM_CHANNELS) {
|
||||
DEBUG_MSG("Setting default channel and radio preferences!\n");
|
||||
|
||||
channels.initDefaults();
|
||||
|
||||
radioConfig.has_preferences = true;
|
||||
}
|
||||
|
||||
channels.onConfigChanged();
|
||||
@@ -195,6 +196,9 @@ 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;
|
||||
@@ -203,12 +207,13 @@ void NodeDB::init()
|
||||
// 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])
|
||||
// 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
|
||||
// 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)
|
||||
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.
|
||||
@@ -223,7 +228,10 @@ 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
|
||||
|
||||
@@ -367,7 +375,7 @@ void NodeDB::saveChannelsToDisk()
|
||||
FS.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeDB::saveToDisk()
|
||||
@@ -478,7 +486,7 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p)
|
||||
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
||||
void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
{
|
||||
if (mp.which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
if (mp.which_payloadVariant == MeshPacket_decoded_tag && mp.from) {
|
||||
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||
|
||||
NodeInfo *info = getOrCreateNode(getFrom(&mp));
|
||||
@@ -488,7 +496,8 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
info->position.time = mp.rx_time;
|
||||
}
|
||||
|
||||
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
|
||||
if (mp.rx_snr)
|
||||
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,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);
|
||||
|
||||
@@ -115,7 +115,8 @@ void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
||||
packetPool.release(p);
|
||||
}
|
||||
|
||||
void Router::setReceivedMessage() {
|
||||
void Router::setReceivedMessage()
|
||||
{
|
||||
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
|
||||
}
|
||||
|
||||
@@ -123,9 +124,13 @@ 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();
|
||||
if (fromRadioQueue.enqueue(p, 0)) {
|
||||
printPacket("Enqueued local", p);
|
||||
setReceivedMessage();
|
||||
} else {
|
||||
printPacket("BUG! fromRadioQueue is full! Discarding!", p);
|
||||
packetPool.release(p);
|
||||
}
|
||||
return ERRNO_OK;
|
||||
} else if (!iface) {
|
||||
// We must be sending to remote nodes also, fail if no interface found
|
||||
@@ -143,9 +148,10 @@ ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
}
|
||||
}
|
||||
|
||||
void printBytes(const char *label, const uint8_t *p, size_t numbytes) {
|
||||
void printBytes(const char *label, const uint8_t *p, size_t numbytes)
|
||||
{
|
||||
DEBUG_MSG("%s: ", label);
|
||||
for(size_t i = 0; i < numbytes; i++)
|
||||
for (size_t i = 0; i < numbytes; i++)
|
||||
DEBUG_MSG("%02x ", p[i]);
|
||||
DEBUG_MSG("\n");
|
||||
}
|
||||
@@ -189,7 +195,7 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
return ERRNO_TOO_LARGE;
|
||||
}
|
||||
|
||||
//printBytes("plaintext", bytes, numbytes);
|
||||
// printBytes("plaintext", bytes, numbytes);
|
||||
|
||||
auto hash = channels.setActiveByIndex(p->channel);
|
||||
if (hash < 0) {
|
||||
@@ -247,19 +253,18 @@ bool Router::perhapsDecode(MeshPacket *p)
|
||||
rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
|
||||
crypto->decrypt(p->from, p->id, rawSize, bytes);
|
||||
|
||||
//printBytes("plaintext", bytes, p->encrypted.size);
|
||||
// printBytes("plaintext", bytes, p->encrypted.size);
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
memset(&p->decoded, 0, sizeof(p->decoded));
|
||||
memset(&p->decoded, 0, sizeof(p->decoded));
|
||||
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
|
||||
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
|
||||
} else if(p->decoded.portnum == PortNum_UNKNOWN_APP) {
|
||||
} else if (p->decoded.portnum == PortNum_UNKNOWN_APP) {
|
||||
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
|
||||
}
|
||||
else {
|
||||
} 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
|
||||
p->channel = chIndex; // change to store the index instead of the hash
|
||||
printPacket("decoded message", p);
|
||||
return true;
|
||||
}
|
||||
@@ -285,7 +290,7 @@ 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);
|
||||
bool decoded = perhapsDecode(p);
|
||||
if (decoded) {
|
||||
// parsing was successful, queue for our recipient
|
||||
printPacket("handleReceived", p);
|
||||
@@ -293,18 +298,20 @@ void Router::handleReceived(MeshPacket *p)
|
||||
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
|
||||
// sniffReceived(p);
|
||||
MeshPlugin::callPlugins(*p);
|
||||
} else {
|
||||
DEBUG_MSG("packet decoding failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Router::perhapsHandleReceived(MeshPacket *p)
|
||||
{
|
||||
assert(radioConfig.has_preferences);
|
||||
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, getFrom(p));
|
||||
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, p->from);
|
||||
|
||||
if (ignore)
|
||||
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);
|
||||
else if (ignore |= shouldFilterReceived(p)) {
|
||||
// DEBUG_MSG("Incoming message was filtered 0x%x\n", p->from);
|
||||
DEBUG_MSG("Incoming message was filtered 0x%x\n", p->from);
|
||||
}
|
||||
|
||||
// Note: we avoid calling shouldFilterReceived if we are supposed to ignore certain nodes - because some overrides might
|
||||
|
||||
@@ -37,8 +37,8 @@ bool SX1262Interface::init()
|
||||
#ifndef SX1262_E22
|
||||
float tcxoVoltage = 0; // None - we use an XTAL
|
||||
#else
|
||||
float tcxoVoltage =
|
||||
1.8; // E22 uses DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
|
||||
// Use DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
|
||||
float tcxoVoltage = 1.8;
|
||||
#endif
|
||||
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
|
||||
|
||||
@@ -142,6 +142,7 @@ void SX1262Interface::addReceiveMetadata(MeshPacket *mp)
|
||||
{
|
||||
// DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
}
|
||||
|
||||
/** We override to turn on transmitter power as needed.
|
||||
|
||||
@@ -31,7 +31,9 @@ template <class T> class TypedQueue
|
||||
|
||||
bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; }
|
||||
|
||||
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY)
|
||||
/** euqueue a packet. Also, maxWait used to default to portMAX_DELAY, but we now want to callers to THINK about what blocking
|
||||
* they want */
|
||||
bool enqueue(T x, TickType_t maxWait)
|
||||
{
|
||||
if (reader) {
|
||||
reader->setInterval(0);
|
||||
|
||||
@@ -25,6 +25,7 @@ typedef struct _AdminMessage {
|
||||
Channel get_channel_response;
|
||||
bool confirm_set_channel;
|
||||
bool confirm_set_radio;
|
||||
bool exit_simulator;
|
||||
};
|
||||
} AdminMessage;
|
||||
|
||||
@@ -47,6 +48,7 @@ extern "C" {
|
||||
#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) \
|
||||
@@ -58,7 +60,8 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_respons
|
||||
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, 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,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
|
||||
|
||||
@@ -125,7 +125,7 @@ extern const pb_msgdesc_t ChannelFile_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define LegacyRadioConfig_size 4
|
||||
#define LegacyRadioConfig_LegacyPreferences_size 2
|
||||
#define DeviceState_size 5056
|
||||
#define DeviceState_size 4920
|
||||
#define ChannelFile_size 832
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -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
|
||||
@@ -38,7 +57,9 @@ typedef enum _Routing_Error {
|
||||
Routing_Error_MAX_RETRANSMIT = 5,
|
||||
Routing_Error_NO_CHANNEL = 6,
|
||||
Routing_Error_TOO_LARGE = 7,
|
||||
Routing_Error_NO_RESPONSE = 8
|
||||
Routing_Error_NO_RESPONSE = 8,
|
||||
Routing_Error_BAD_REQUEST = 32,
|
||||
Routing_Error_NOT_AUTHORIZED = 33
|
||||
} Routing_Error;
|
||||
|
||||
typedef enum _MeshPacket_Priority {
|
||||
@@ -84,7 +105,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;
|
||||
@@ -112,6 +133,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;
|
||||
@@ -130,6 +152,7 @@ typedef struct _MeshPacket {
|
||||
uint8_t hop_limit;
|
||||
bool want_ack;
|
||||
MeshPacket_Priority priority;
|
||||
int32_t rx_rssi;
|
||||
} MeshPacket;
|
||||
|
||||
typedef struct _NodeInfo {
|
||||
@@ -138,7 +161,6 @@ typedef struct _NodeInfo {
|
||||
User user;
|
||||
bool has_position;
|
||||
Position position;
|
||||
uint32_t next_hop;
|
||||
float snr;
|
||||
} NodeInfo;
|
||||
|
||||
@@ -174,6 +196,10 @@ 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))
|
||||
@@ -183,8 +209,8 @@ typedef struct _ToRadio {
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_Brownout+1))
|
||||
|
||||
#define _Routing_Error_MIN Routing_Error_NONE
|
||||
#define _Routing_Error_MAX Routing_Error_NO_RESPONSE
|
||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_NO_RESPONSE+1))
|
||||
#define _Routing_Error_MAX Routing_Error_NOT_AUTHORIZED
|
||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_NOT_AUTHORIZED+1))
|
||||
|
||||
#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET
|
||||
#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX
|
||||
@@ -201,23 +227,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 MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
|
||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0}
|
||||
#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 MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
|
||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0}
|
||||
#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}}
|
||||
@@ -238,7 +264,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
|
||||
@@ -256,6 +282,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
|
||||
@@ -267,10 +294,10 @@ extern "C" {
|
||||
#define MeshPacket_hop_limit_tag 10
|
||||
#define MeshPacket_want_ack_tag 11
|
||||
#define MeshPacket_priority_tag 12
|
||||
#define MeshPacket_rx_rssi_tag 13
|
||||
#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
|
||||
@@ -299,7 +326,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
|
||||
|
||||
@@ -338,7 +366,8 @@ X(a, STATIC, SINGULAR, FIXED32, rx_time, 7) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \
|
||||
X(a, STATIC, SINGULAR, UENUM, priority, 12)
|
||||
X(a, STATIC, SINGULAR, UENUM, priority, 12) \
|
||||
X(a, STATIC, SINGULAR, INT32, rx_rssi, 13)
|
||||
#define MeshPacket_CALLBACK NULL
|
||||
#define MeshPacket_DEFAULT NULL
|
||||
#define MeshPacket_payloadVariant_decoded_MSGTYPE Data
|
||||
@@ -347,7 +376,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
|
||||
@@ -359,7 +387,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) \
|
||||
@@ -427,16 +455,16 @@ 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 MeshPacket_size 309
|
||||
#define NodeInfo_size 126
|
||||
#define MyNodeInfo_size 89
|
||||
#define LogRecord_size 81
|
||||
#define FromRadio_size 307
|
||||
#define ToRadio_size 301
|
||||
#define FromRadio_size 318
|
||||
#define ToRadio_size 312
|
||||
|
||||
#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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <bluefruit.h>
|
||||
|
||||
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include "mesh/PhoneAPI.h"
|
||||
|
||||
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
|
||||
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
|
||||
@@ -213,6 +213,7 @@ void NRF52Bluetooth::setup()
|
||||
{
|
||||
// Initialise the Bluefruit module
|
||||
DEBUG_MSG("Initialise the Bluefruit nRF52 module\n");
|
||||
Bluefruit.autoConnLed(false);
|
||||
Bluefruit.begin();
|
||||
|
||||
// Set the advertised device name (keep it short!)
|
||||
@@ -224,7 +225,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();
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "graphics/TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include <assert.h>
|
||||
@@ -9,179 +5,182 @@
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef NRF52840_XXAA
|
||||
// #include <nrf52840.h>
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifdef BQ25703A_ADDR
|
||||
#include "BQ25713.h"
|
||||
#endif
|
||||
|
||||
// #define USE_SOFTDEVICE
|
||||
|
||||
static inline void debugger_break(void)
|
||||
{
|
||||
__asm volatile("bkpt #0x01\n\t"
|
||||
"mov pc, lr\n\t");
|
||||
static inline void debugger_break(void) {
|
||||
__asm volatile(
|
||||
"bkpt #0x01\n\t"
|
||||
"mov pc, lr\n\t");
|
||||
}
|
||||
|
||||
// handle standard gcc assert failures
|
||||
void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *failedexpr)
|
||||
{
|
||||
DEBUG_MSG("assert failed %s: %d, %s, test=%s\n", file, line, func, failedexpr);
|
||||
// debugger_break(); FIXME doesn't work, possibly not for segger
|
||||
while (1)
|
||||
; // FIXME, reboot!
|
||||
void __attribute__((noreturn))
|
||||
__assert_func(const char *file, int line, const char *func,
|
||||
const char *failedexpr) {
|
||||
DEBUG_MSG("assert failed %s: %d, %s, test=%s\n", file, line, func,
|
||||
failedexpr);
|
||||
// debugger_break(); FIXME doesn't work, possibly not for segger
|
||||
while (1)
|
||||
; // FIXME, reboot!
|
||||
}
|
||||
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
ble_gap_addr_t addr;
|
||||
|
||||
#ifdef USE_SOFTDEVICE
|
||||
uint32_t res = sd_ble_gap_addr_get(&addr);
|
||||
assert(res == NRF_SUCCESS);
|
||||
void getMacAddr(uint8_t *dmac) {
|
||||
ble_gap_addr_t addr;
|
||||
if (sd_ble_gap_addr_get(&addr) == NRF_SUCCESS) {
|
||||
memcpy(dmac, addr.addr, 6);
|
||||
#else
|
||||
} else {
|
||||
const uint8_t *src = (const uint8_t *)NRF_FICR->DEVICEADDR;
|
||||
dmac[5] = src[0];
|
||||
dmac[4] = src[1];
|
||||
dmac[3] = src[2];
|
||||
dmac[2] = src[3];
|
||||
dmac[1] = src[4];
|
||||
dmac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
|
||||
#endif
|
||||
dmac[0] = src[5] |
|
||||
0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
|
||||
}
|
||||
}
|
||||
|
||||
NRF52Bluetooth *nrf52Bluetooth;
|
||||
|
||||
static bool bleOn = false;
|
||||
static const bool useSoftDevice = false; // Set to false for easier debugging
|
||||
static const bool useSoftDevice = true; // Set to false for easier debugging
|
||||
|
||||
void setBluetoothEnable(bool on)
|
||||
{
|
||||
if (on != bleOn) {
|
||||
if (on) {
|
||||
if (!nrf52Bluetooth) {
|
||||
if (!useSoftDevice)
|
||||
DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n");
|
||||
else {
|
||||
nrf52Bluetooth = new NRF52Bluetooth();
|
||||
nrf52Bluetooth->setup();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nrf52Bluetooth)
|
||||
nrf52Bluetooth->shutdown();
|
||||
void setBluetoothEnable(bool on) {
|
||||
if (on != bleOn) {
|
||||
if (on) {
|
||||
if (!nrf52Bluetooth) {
|
||||
if (!useSoftDevice)
|
||||
DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n");
|
||||
else {
|
||||
nrf52Bluetooth = new NRF52Bluetooth();
|
||||
nrf52Bluetooth->setup();
|
||||
}
|
||||
bleOn = on;
|
||||
}
|
||||
} else {
|
||||
if (nrf52Bluetooth) nrf52Bluetooth->shutdown();
|
||||
}
|
||||
bleOn = on;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override printf to use the SEGGER output library
|
||||
*/
|
||||
int printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
auto res = SEGGER_RTT_vprintf(0, fmt, &args);
|
||||
va_end(args);
|
||||
return res;
|
||||
int printf(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
auto res = SEGGER_RTT_vprintf(0, fmt, &args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
#include "BQ25713.h"
|
||||
void initBrownout() {
|
||||
auto vccthresh = POWER_POFCON_THRESHOLD_V28;
|
||||
|
||||
void initBrownout()
|
||||
{
|
||||
auto vccthresh = POWER_POFCON_THRESHOLD_V28;
|
||||
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 {
|
||||
uint32_t pof_flags = POWER_POFCON_POF_Enabled | (vccthresh << POWER_POFCON_THRESHOLD_Pos);
|
||||
|
||||
#ifdef POWER_POFCON_THRESHOLDVDDH_Msk
|
||||
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);
|
||||
}
|
||||
pof_flags |= (vcchthresh << POWER_POFCON_THRESHOLDVDDH_Pos);
|
||||
#endif
|
||||
|
||||
NRF_POWER->POFCON = pof_flags;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
void checkSDEvents() {
|
||||
if (useSoftDevice) {
|
||||
uint32_t evt;
|
||||
while (NRF_SUCCESS == 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);
|
||||
default:
|
||||
DEBUG_MSG("Unexpected SDevt %d\n", evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (NRF_POWER->EVENTS_POFWARN)
|
||||
recordCriticalError(CriticalErrorCode_Brownout);
|
||||
}
|
||||
}
|
||||
|
||||
void nrf52Loop()
|
||||
{
|
||||
checkSDEvents();
|
||||
}
|
||||
void nrf52Loop() { checkSDEvents(); }
|
||||
|
||||
void nrf52Setup()
|
||||
{
|
||||
void nrf52Setup() {
|
||||
auto why = NRF_POWER->RESETREAS;
|
||||
// per
|
||||
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html
|
||||
DEBUG_MSG("Reset reason: 0x%x\n", why);
|
||||
|
||||
auto why = NRF_POWER->RESETREAS;
|
||||
// per https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html
|
||||
DEBUG_MSG("Reset reason: 0x%x\n", why);
|
||||
|
||||
// Per https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse
|
||||
// This is the recommended setting for Monitor Mode Debugging
|
||||
NVIC_SetPriority(DebugMonitor_IRQn, 6UL);
|
||||
// Per
|
||||
// https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse
|
||||
// This is the recommended setting for Monitor Mode Debugging
|
||||
NVIC_SetPriority(DebugMonitor_IRQn, 6UL);
|
||||
|
||||
#ifdef BQ25703A_ADDR
|
||||
auto *bq = new BQ25713();
|
||||
if (!bq->setup())
|
||||
DEBUG_MSG("ERROR! Charge controller init failed\n");
|
||||
auto *bq = new BQ25713();
|
||||
if (!bq->setup()) DEBUG_MSG("ERROR! Charge controller init failed\n");
|
||||
#endif
|
||||
|
||||
// Init random seed
|
||||
// FIXME - use this to get random numbers
|
||||
// #include "nrf_rng.h"
|
||||
// uint32_t r;
|
||||
// ble_controller_rand_vector_get_blocking(&r, sizeof(r));
|
||||
// randomSeed(r);
|
||||
DEBUG_MSG("FIXME, call randomSeed\n");
|
||||
// ::printf("TESTING PRINTF\n");
|
||||
// Init random seed
|
||||
// FIXME - use this to get random numbers
|
||||
// #include "nrf_rng.h"
|
||||
// uint32_t r;
|
||||
// ble_controller_rand_vector_get_blocking(&r, sizeof(r));
|
||||
// randomSeed(r);
|
||||
DEBUG_MSG("FIXME, call randomSeed\n");
|
||||
// ::printf("TESTING PRINTF\n");
|
||||
|
||||
initBrownout();
|
||||
initBrownout();
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint64_t msecToWake)
|
||||
{
|
||||
// FIXME, configure RTC or button press to wake us
|
||||
// FIXME, power down SPI, I2C, RAMs
|
||||
Wire.end();
|
||||
SPI.end();
|
||||
Serial.end();
|
||||
Serial1.end();
|
||||
void cpuDeepSleep(uint64_t msecToWake) {
|
||||
// FIXME, configure RTC or button press to wake us
|
||||
// FIXME, power down SPI, I2C, RAMs
|
||||
#ifndef NO_WIRE
|
||||
Wire.end();
|
||||
#endif
|
||||
SPI.end();
|
||||
// This may cause crashes as debug messages continue to flow.
|
||||
Serial.end();
|
||||
|
||||
// FIXME, use system off mode with ram retention for key state?
|
||||
// FIXME, use non-init RAM per
|
||||
// https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
|
||||
#ifdef PIN_SERIAL_RX1
|
||||
Serial1.end();
|
||||
#endif
|
||||
setBluetoothEnable(false);
|
||||
// FIXME, use system off mode with ram retention for key state?
|
||||
// FIXME, use non-init RAM per
|
||||
// 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) {
|
||||
DEBUG_MSG("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n");
|
||||
NRF_POWER->SYSTEMOFF = 1;
|
||||
}
|
||||
auto ok = sd_power_system_off();
|
||||
if (ok != NRF_SUCCESS) {
|
||||
DEBUG_MSG(
|
||||
"FIXME: Ignoring soft device (EasyDMA pending?) and forcing "
|
||||
"system-off!\n");
|
||||
NRF_POWER->SYSTEMOFF = 1;
|
||||
}
|
||||
|
||||
// The following code should not be run, because we are off
|
||||
while (1) {
|
||||
delay(5000);
|
||||
DEBUG_MSG(".");
|
||||
}
|
||||
// The following code should not be run, because we are off
|
||||
while (1) {
|
||||
delay(5000);
|
||||
DEBUG_MSG(".");
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,10 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifdef PORTDUINO
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
AdminPlugin *adminPlugin;
|
||||
|
||||
void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
|
||||
@@ -51,20 +55,35 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag
|
||||
break;
|
||||
|
||||
case AdminMessage_set_channel_tag:
|
||||
DEBUG_MSG("Client is setting channel\n");
|
||||
handleSetChannel(r->set_channel);
|
||||
DEBUG_MSG("Client is setting channel %d\n", r->set_channel.index);
|
||||
if (r->set_channel.index < 0 || r->set_channel.index >= MAX_NUM_CHANNELS)
|
||||
reply = allocErrorResponse(Routing_Error_BAD_REQUEST, &mp);
|
||||
else
|
||||
handleSetChannel(r->set_channel);
|
||||
break;
|
||||
|
||||
case AdminMessage_get_channel_request_tag:
|
||||
DEBUG_MSG("Client is getting channel %d\n", r->get_channel_request - 1);
|
||||
handleGetChannel(mp, r->get_channel_request - 1);
|
||||
case AdminMessage_get_channel_request_tag: {
|
||||
uint32_t i = r->get_channel_request - 1;
|
||||
DEBUG_MSG("Client is getting channel %u\n", i);
|
||||
if (i >= MAX_NUM_CHANNELS)
|
||||
reply = allocErrorResponse(Routing_Error_BAD_REQUEST, &mp);
|
||||
else
|
||||
handleGetChannel(mp, i);
|
||||
break;
|
||||
}
|
||||
|
||||
case AdminMessage_get_radio_request_tag:
|
||||
DEBUG_MSG("Client is getting radio\n");
|
||||
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);
|
||||
@@ -102,8 +121,7 @@ void AdminPlugin::handleSetChannel(const Channel &cc)
|
||||
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 {
|
||||
} else {
|
||||
channels.onConfigChanged(); // tell the radios about this change
|
||||
nodeDB.saveChannelsToDisk();
|
||||
}
|
||||
@@ -126,5 +144,5 @@ MeshPacket *AdminPlugin::allocReply()
|
||||
AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = "admin";
|
||||
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,48 +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);
|
||||
}
|
||||
#else
|
||||
return INT32_MAX;
|
||||
#endif
|
||||
|
||||
return (25);
|
||||
}
|
||||
|
||||
void ExternalNotificationPlugin::setExternalOn()
|
||||
@@ -140,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
|
||||
|
||||
@@ -156,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();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -18,17 +18,16 @@ bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *
|
||||
printPacket("Delivering rx packet", &mp);
|
||||
service.handleFromRadio(&mp);
|
||||
}
|
||||
|
||||
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
|
||||
MeshPacket *RoutingPlugin::allocReply()
|
||||
{
|
||||
assert(currentRequest);
|
||||
|
||||
// We only consider making replies if the request was a legit routing packet (not just something we were sniffing)
|
||||
if(currentRequest->decoded.portnum == PortNum_ROUTING_APP) {
|
||||
if (currentRequest->decoded.portnum == PortNum_ROUTING_APP) {
|
||||
assert(0); // 1.2 refactoring fixme, Not sure if anything needs this yet?
|
||||
// return allocDataProtobuf(u);
|
||||
}
|
||||
@@ -37,26 +36,12 @@ MeshPacket *RoutingPlugin::allocReply()
|
||||
|
||||
void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
{
|
||||
Routing c = Routing_init_default;
|
||||
|
||||
c.error_reason = err;
|
||||
|
||||
auto p = allocDataProtobuf(c);
|
||||
p->priority = MeshPacket_Priority_ACK;
|
||||
|
||||
p->hop_limit = 0; // Assume just immediate neighbors for now
|
||||
p->to = to;
|
||||
p->decoded.request_id = idFrom;
|
||||
p->channel = chIndex;
|
||||
DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
auto p = allocAckNak(err, to, idFrom, chIndex);
|
||||
|
||||
router->sendLocal(p); // we sometimes send directly to the local node
|
||||
}
|
||||
|
||||
RoutingPlugin::RoutingPlugin()
|
||||
: ProtobufPlugin("routing", PortNum_ROUTING_APP, Routing_fields)
|
||||
RoutingPlugin::RoutingPlugin() : ProtobufPlugin("routing", PortNum_ROUTING_APP, Routing_fields)
|
||||
{
|
||||
isPromiscuous = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -180,9 +186,19 @@ bool SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
}
|
||||
|
||||
} else {
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
|
||||
if (radioConfig.preferences.serialplugin_mode == 0 || radioConfig.preferences.serialplugin_mode == 1) {
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
|
||||
} else if (radioConfig.preferences.serialplugin_mode == 10) {
|
||||
/*
|
||||
@jobionekabnoi
|
||||
Add code here to handle what gets sent out to the serial interface.
|
||||
Format it the way you want.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,9 +35,9 @@ int32_t RangeTestPlugin::runOnce()
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
//radioConfig.preferences.range_test_plugin_enabled = 1;
|
||||
//radioConfig.preferences.range_test_plugin_sender = 45;
|
||||
//radioConfig.preferences.range_test_plugin_save = 1;
|
||||
// radioConfig.preferences.range_test_plugin_enabled = 1;
|
||||
// radioConfig.preferences.range_test_plugin_sender = 45;
|
||||
// radioConfig.preferences.range_test_plugin_save = 1;
|
||||
|
||||
// Fixed position is useful when testing indoors.
|
||||
// radioConfig.preferences.fixed_position = 1;
|
||||
@@ -112,7 +112,7 @@ void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
packetSequence++;
|
||||
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "seq %d", packetSequence);
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "seq %u", packetSequence);
|
||||
|
||||
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, heartbeatString, p->decoded.payload.size);
|
||||
@@ -290,7 +290,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
fileToAppend.printf("??:??:??,"); // Time
|
||||
}
|
||||
|
||||
fileToAppend.printf("%d,", getFrom(&mp)); // 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,89 +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.
|
||||
|
||||
attn @mc-hamster I moved this back inside the comment because I don't think it was intended to checkin. It was forcing all
|
||||
nodes to be running this and turning off is_router.
|
||||
|
||||
radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
radioConfig.preferences.is_router = 0;
|
||||
*/
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
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
|
||||
storeForwardPluginRadio = new StoreForwardPluginRadio();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
DEBUG_MSG("Store & Forward Plugin - Sending heartbeat\n");
|
||||
|
||||
DEBUG_MSG("Store & Forward Plugin - Sending heartbeat\n");
|
||||
storeForwardPlugin->sendPayload();
|
||||
|
||||
// storeForwardPluginRadio->sendPayloadHeartbeat();
|
||||
if(storeForwardPluginRadio)
|
||||
storeForwardPluginRadio->sendPayload();
|
||||
|
||||
return (1 * 60 * 1000);
|
||||
}
|
||||
return (4 * 60 * 1000);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -110,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.
|
||||
@@ -228,41 +180,32 @@ void StoreForwardPlugin::sawNodeReport()
|
||||
}
|
||||
}
|
||||
|
||||
MeshPacket *StoreForwardPluginRadio::allocReply()
|
||||
MeshPacket *StoreForwardPlugin::allocReply()
|
||||
{
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
return reply; // attn @mc-hamster this code was commented out and was causing memory corruption
|
||||
return reply;
|
||||
}
|
||||
|
||||
void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
void StoreForwardPlugin::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
/*
|
||||
MeshPacket *p = this->allocReply(); // attn @mc-hamster, I moved inside the commented block to prevent leaking memory
|
||||
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");
|
||||
/*
|
||||
*/
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "1");
|
||||
|
||||
// p->decoded.data.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
// memcpy(p->decoded.data.payload.bytes, "1", 1);
|
||||
|
||||
// service.sendToMesh(p);
|
||||
}
|
||||
|
||||
void StoreForwardPluginRadio::sendPayloadHeartbeat(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
DEBUG_MSG("Sending S&F Heartbeat\n");
|
||||
MeshPacket *p = this->allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
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) {
|
||||
@@ -274,7 +217,7 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
printPacket("----- PACKET FROM RADIO -----", &mp);
|
||||
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) {
|
||||
@@ -288,6 +231,10 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
DEBUG_MSG("Packet came from - PortNum_POSITION_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_NODEINFO_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_NODEINFO_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_ROUTING_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_ROUTING_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_ADMIN_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_ADMIN_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_REPLY_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_REPLY_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_IP_TUNNEL_APP) {
|
||||
@@ -322,3 +269,46 @@ 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) {
|
||||
|
||||
// Router
|
||||
if (radioConfig.preferences.is_router) {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Router\n");
|
||||
if (ESP.getPsramSize()) {
|
||||
if (ESP.getFreePsram() >= 1024 * 1024) {
|
||||
|
||||
// Do the startup here
|
||||
|
||||
this->populatePSRAM();
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device doesn't have PSRAM.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
}
|
||||
|
||||
// Client
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Client\n");
|
||||
}
|
||||
}
|
||||
#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,41 +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);
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayloadHeartbeat(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
|
||||
|
||||
@@ -80,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());
|
||||
}
|
||||
|
||||
52
variants/lora_isp4520/variant.cpp
Normal file
52
variants/lora_isp4520/variant.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "variant.h"
|
||||
#include "nrf.h"
|
||||
#include "wiring_constants.h"
|
||||
#include "wiring_digital.h"
|
||||
|
||||
const uint32_t g_ADigitalPinMap[] = {
|
||||
25, // D0 SPI_MISO
|
||||
24, // D1 SPI_NSS
|
||||
23, // D2 SPI_SCK
|
||||
4, // D3 VBAT
|
||||
11, // D4 DIO1
|
||||
27, // D5 BUSY
|
||||
19, // D6 NRESET
|
||||
12, // D7 BUTTON2
|
||||
22, // D8 BUTTON3
|
||||
26, // D9 SPI_MOSI
|
||||
31, // D10 UART_RX
|
||||
2, // D11 UART_TX
|
||||
10, // D12 LED1 GREEN
|
||||
17, // D13 LED2 RED
|
||||
9, // D14 BUZZER
|
||||
7, // D15 BUTTON1
|
||||
};
|
||||
|
||||
#include <initializer_list>
|
||||
void initVariant()
|
||||
{
|
||||
for (int i : {PIN_LED1, PIN_LED2}) {
|
||||
pinMode(i, OUTPUT);
|
||||
ledOff(i);
|
||||
}
|
||||
}
|
||||
99
variants/lora_isp4520/variant.h
Normal file
99
variants/lora_isp4520/variant.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library 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 Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _VARIANT_LORA_ISP4520_
|
||||
#define _VARIANT_LORA_ISP4520_
|
||||
|
||||
#define HW_VERSION_US 1
|
||||
#undef HW_VERSION
|
||||
#define HW_VERSION "1.0"
|
||||
|
||||
#define USE_SEGGER
|
||||
/*----------------------------------------------------------------------------
|
||||
* Headers
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "WVariant.h"
|
||||
|
||||
#define USE_LFXO
|
||||
|
||||
//#define USE_SEGGER
|
||||
|
||||
// Number of pins defined in PinDescription array
|
||||
#define PINS_COUNT (16)
|
||||
#define NUM_DIGITAL_PINS (16)
|
||||
#define NUM_ANALOG_INPUTS (1)
|
||||
#define NUM_ANALOG_OUTPUTS (1)
|
||||
|
||||
/*
|
||||
* SPI Interfaces
|
||||
*/
|
||||
#define SPI_INTERFACES_COUNT 1
|
||||
|
||||
// These are in arduino pin numbers,
|
||||
// translation in g_ADigitalPinMap in variants.cpp
|
||||
#define PIN_SPI_MISO (0)
|
||||
#define PIN_SPI_MOSI (9)
|
||||
#define PIN_SPI_SCK (2)
|
||||
|
||||
/*
|
||||
* Wire Interfaces (I2C)
|
||||
*/
|
||||
#define WIRE_INTERFACES_COUNT 0
|
||||
|
||||
// GPIOs the SX1262 is connected
|
||||
#define SX1262_CS 1 // aka SPI_NSS
|
||||
#define SX1262_DIO1 (4)
|
||||
#define SX1262_BUSY (5)
|
||||
#define SX1262_RESET (6)
|
||||
|
||||
/*
|
||||
* Serial interfaces
|
||||
*/
|
||||
#define PIN_SERIAL_RX (10)
|
||||
#define PIN_SERIAL_TX (11)
|
||||
// LEDs
|
||||
#define PIN_LED1 (12)
|
||||
#define PIN_LED2 (13)
|
||||
#define PIN_BUZZER (14)
|
||||
|
||||
#define LED_BUILTIN PIN_LED1
|
||||
#define LED_CONN PIN_LED2
|
||||
|
||||
#define LED_RED PIN_LED1
|
||||
#define LED_BLUE PIN_LED2
|
||||
|
||||
#define LED_STATE_ON 1 // State when LED is litted
|
||||
|
||||
/*
|
||||
* Buttons
|
||||
*/
|
||||
#define PIN_BUTTON1 (15)
|
||||
#define PIN_BUTTON2 (7)
|
||||
#define PIN_BUTTON3 (8)
|
||||
|
||||
// ADC pin and voltage divider
|
||||
#define BATTERY_PIN 3
|
||||
#define ADC_MULTIPLIER 1.436
|
||||
|
||||
#define SX1262_E22 // Not really an E22 but this board clones using DIO3 for tcxo control
|
||||
|
||||
#define NO_WIRE
|
||||
#define NO_GPS
|
||||
#define NO_SCREEN
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 1
|
||||
minor = 2
|
||||
build = 10
|
||||
build = 13
|
||||
|
||||
Reference in New Issue
Block a user