mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-24 19:50:35 +00:00
Compare commits
150 Commits
v1.2.testi
...
v1.2.45.b6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6740548f3 | ||
|
|
5fe3ec09de | ||
|
|
079843d777 | ||
|
|
bd7171a7a2 | ||
|
|
eaa15076cd | ||
|
|
2fd74d8f47 | ||
|
|
0e91d39b27 | ||
|
|
52d7a6b8e4 | ||
|
|
472e880280 | ||
|
|
189889489b | ||
|
|
0d758347af | ||
|
|
3266d57cfb | ||
|
|
f2c9c5553c | ||
|
|
bcdc42816b | ||
|
|
b04e313665 | ||
|
|
700e799125 | ||
|
|
a9f8080ee7 | ||
|
|
9f450cb1c5 | ||
|
|
388f19da79 | ||
|
|
4f11598112 | ||
|
|
bcb54b643f | ||
|
|
04d3f44179 | ||
|
|
5110a6de82 | ||
|
|
04c5ac0d7c | ||
|
|
6d2cd73599 | ||
|
|
057b04a88a | ||
|
|
28af18389b | ||
|
|
2af4c619e1 | ||
|
|
99d529be51 | ||
|
|
39df7108a8 | ||
|
|
72807f0fa0 | ||
|
|
2fe11d4fe8 | ||
|
|
596befff74 | ||
|
|
b2524ceaff | ||
|
|
5f323e8bd1 | ||
|
|
d40b66beac | ||
|
|
afa12d6e87 | ||
|
|
676a6f3bea | ||
|
|
bf0b598908 | ||
|
|
8a79663fa0 | ||
|
|
564262e75b | ||
|
|
a405d81c46 | ||
|
|
aac3143745 | ||
|
|
bb396508a4 | ||
|
|
810740b156 | ||
|
|
19ffddb02e | ||
|
|
5826c52242 | ||
|
|
a6904105f7 | ||
|
|
da8ab82126 | ||
|
|
978bb7aa8b | ||
|
|
32fea4cbd7 | ||
|
|
6e136b9796 | ||
|
|
986d44873a | ||
|
|
2e1746ca0f | ||
|
|
863b60277b | ||
|
|
035f25190b | ||
|
|
3ea03dadb5 | ||
|
|
753ae00ddb | ||
|
|
2759c8d037 | ||
|
|
301f196bca | ||
|
|
32f3682fae | ||
|
|
fc9fc1ee6f | ||
|
|
659286f738 | ||
|
|
17a1262382 | ||
|
|
66b96d2052 | ||
|
|
06892c412c | ||
|
|
5c4d1a88a8 | ||
|
|
eb9e976fab | ||
|
|
451b085c13 | ||
|
|
27dced6a35 | ||
|
|
3c4f3316c0 | ||
|
|
2f607d5a8c | ||
|
|
42f3154079 | ||
|
|
e7e09cb7ed | ||
|
|
c6092ea520 | ||
|
|
29ff778e22 | ||
|
|
d80814a12e | ||
|
|
cfeb0b47e9 | ||
|
|
6f14d017d8 | ||
|
|
cf4e508fb3 | ||
|
|
96fc1f5272 | ||
|
|
5b65fd5754 | ||
|
|
29587d4c4e | ||
|
|
a98bf80c24 | ||
|
|
49869ca044 | ||
|
|
54d4fb7d46 | ||
|
|
5699abc8ad | ||
|
|
6b56583023 | ||
|
|
abe95ae1a4 | ||
|
|
4e8e85c9f1 | ||
|
|
26bb4ffe79 | ||
|
|
c857e5707e | ||
|
|
aaf1570938 | ||
|
|
a8feb40ae9 | ||
|
|
be410a3913 | ||
|
|
069b0d38be | ||
|
|
7cae8dc50f | ||
|
|
70b0a73572 | ||
|
|
72d7142751 | ||
|
|
8367b9b159 | ||
|
|
ad1cbf60b4 | ||
|
|
1c4bf8ac18 | ||
|
|
13199f13c2 | ||
|
|
7f2bbcd95e | ||
|
|
68cb62ab23 | ||
|
|
5a3ff137f9 | ||
|
|
0206e65152 | ||
|
|
b16004dcdf | ||
|
|
844189671f | ||
|
|
e582615eda | ||
|
|
7f51517961 | ||
|
|
2e832774a2 | ||
|
|
7475e3c105 | ||
|
|
80e4bc6289 | ||
|
|
19ee911022 | ||
|
|
cb4d5d580a | ||
|
|
7b3d59569e | ||
|
|
3bc0aaabe4 | ||
|
|
2418fee444 | ||
|
|
b56c5df6e1 | ||
|
|
bc76c79e1e | ||
|
|
d179bda728 | ||
|
|
e60ef655cb | ||
|
|
c15204fed1 | ||
|
|
1f2dc82035 | ||
|
|
218d841511 | ||
|
|
f40c6f21d4 | ||
|
|
6dc4471bec | ||
|
|
4c1b7d4840 | ||
|
|
8ec73e653b | ||
|
|
babc1b3613 | ||
|
|
c27d479a9f | ||
|
|
14224088aa | ||
|
|
b95baadb9a | ||
|
|
c940d22a98 | ||
|
|
28b7bd347a | ||
|
|
a42bb80cf4 | ||
|
|
2a9b2d3b29 | ||
|
|
9c94a324e5 | ||
|
|
f07f3ae94b | ||
|
|
b6c2cd6caa | ||
|
|
a66ad8a9d9 | ||
|
|
8e3281a658 | ||
|
|
6e27856daa | ||
|
|
ce2d603def | ||
|
|
fa00e21f49 | ||
|
|
c4878671e3 | ||
|
|
57ef3b499f | ||
|
|
6c956591f8 | ||
|
|
640cc82103 |
11
.devcontainer/Dockerfile
Normal file
11
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/ubuntu/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Ubuntu version: bionic, focal
|
||||
ARG VARIANT="focal"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get -y install python3-distutils python3-pip
|
||||
RUN pip3 install platformio meshtastic adafruit-nrfutil
|
||||
RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v3.15.8/protoc-3.15.8-linux-x86_64.zip -O /tmp/protoc.zip && cd /tmp && unzip protoc.zip && chmod a+x bin/protoc && cp bin/protoc /usr/local/bin
|
||||
32
.devcontainer/devcontainer.json
Normal file
32
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,32 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/ubuntu
|
||||
{
|
||||
"name": "Ubuntu",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
// Update 'VARIANT' to pick an Ubuntu version: focal, bionic
|
||||
"args": { "VARIANT": "focal" }
|
||||
},
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"platformio.platformio-ide",
|
||||
"xaver.clang-format"
|
||||
],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "uname -a",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "vscode",
|
||||
|
||||
"postCreateCommand": "git submodule update --init"
|
||||
}
|
||||
13
.github/actions/initbuild/action.yml
vendored
13
.github/actions/initbuild/action.yml
vendored
@@ -24,12 +24,13 @@ runs:
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
|
||||
- name: Cache platformio
|
||||
uses: actions/cache@v1
|
||||
id: cache-platformio # needed in if test
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-platformio
|
||||
# Don't cache for now because I want to be lazy with portuino updates githashes
|
||||
# - name: Cache platformio
|
||||
# uses: actions/cache@v1
|
||||
# id: cache-platformio # needed in if test
|
||||
# with:
|
||||
# path: ~/.platformio
|
||||
# key: ${{ runner.os }}-platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
|
||||
27
.github/workflows/main.yml
vendored
27
.github/workflows/main.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
# - name: Startup
|
||||
# run: echo "No action setup currently needed, skipping..."
|
||||
|
||||
build:
|
||||
ci-build:
|
||||
# needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -36,6 +36,10 @@ jobs:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
#- name: Install linux apt packages
|
||||
# run: |
|
||||
# sudo apt-get install -y libgpiod-dev
|
||||
|
||||
- name: Upgrade python tools
|
||||
# We actually want to run this every time
|
||||
# if: steps.cache-pip.outputs.cache-hit != 'true'
|
||||
@@ -43,12 +47,12 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
|
||||
- name: Cache platformio
|
||||
uses: actions/cache@v1
|
||||
id: cache-platformio # needed in if test
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-platformio
|
||||
# - name: Cache platformio
|
||||
# uses: actions/cache@v1
|
||||
# id: cache-platformio # needed in if test
|
||||
# with:
|
||||
# path: ~/.platformio
|
||||
# key: ${{ runner.os }}-platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
@@ -74,9 +78,16 @@ jobs:
|
||||
- name: Build everything
|
||||
run: bin/build-all.sh
|
||||
|
||||
- name: Store release zip as an artifact
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: built
|
||||
path: release/archive/firmware-*.zip
|
||||
retention-days: 30
|
||||
|
||||
- name: Store debugging elf files as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: debug-elfs
|
||||
path: release/archive/elfs-*.zip
|
||||
retention-days: 7
|
||||
|
||||
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -9,10 +9,10 @@ on:
|
||||
branches:
|
||||
- "!*"
|
||||
tags:
|
||||
- "v*"
|
||||
- "v1*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
release-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
|
||||
# Will be available in steps.version.outputs.version
|
||||
- name: Get version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py)"
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
|
||||
- name: Build everything
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Add artifact to release
|
||||
- name: Add bins to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
@@ -77,4 +77,14 @@ jobs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: release/archive/firmware-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: firmware-${{ steps.version.outputs.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: Add debug elfs to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: release/archive/elfs-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -9,6 +9,8 @@ main/credentials.h
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
.idea/workspace.xml
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.autotools
|
||||
@@ -19,4 +21,5 @@ Thumbs.db
|
||||
nanopb*
|
||||
flash.uf2
|
||||
cmake-build*
|
||||
__pycache__
|
||||
__pycache__
|
||||
|
||||
|
||||
162
.idea/workspace.xml
generated
162
.idea/workspace.xml
generated
@@ -1,162 +0,0 @@
|
||||
<?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" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1pmWHw2wau2TbdKvXvmQUB0EUE9" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="ASKED_ADD_EXTERNAL_FILES" value="true" />
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="cf.advertisement.text.overridden" value="true" />
|
||||
<property name="cf.first.check.clang-format" value="false" />
|
||||
<property name="node.js.detected.package.eslint" value="true" />
|
||||
<property name="node.js.detected.package.tslint" value="true" />
|
||||
<property name="node.js.path.for.package.eslint" value="project" />
|
||||
<property name="node.js.path.for.package.tslint" value="project" />
|
||||
<property name="node.js.selected.package.eslint" value="(autodetect)" />
|
||||
<property name="node.js.selected.package.tslint" value="(autodetect)" />
|
||||
<property name="settings.editor.selected.configurable" value="CMakeSettings" />
|
||||
</component>
|
||||
<component name="RunManager" selected="GDB Remote Debug.gdbremote-localhost-2345">
|
||||
<configuration default="true" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="gdbremote-localhost-2345" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Z_DUMMY_TARGET" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Z_DUMMY_TARGET" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Z_DUMMY_TARGET">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="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" />
|
||||
<workItem from="1617115374907" duration="357000" />
|
||||
<workItem from="1617115747078" duration="1391000" />
|
||||
<workItem from="1617117632667" duration="307000" />
|
||||
<workItem from="1617160691713" duration="1016000" />
|
||||
<workItem from="1617279002260" duration="1626000" />
|
||||
<workItem from="1617425689081" duration="1896000" />
|
||||
<workItem from="1617437366919" duration="1182000" />
|
||||
<workItem from="1618544034975" duration="1185000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="oldMeFiltersMigrated" value="true" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||
<line>53</line>
|
||||
<option name="timeStamp" value="6" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||
<line>37</line>
|
||||
<option name="timeStamp" value="7" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mqtt/MQTT.cpp</url>
|
||||
<line>166</line>
|
||||
<option name="timeStamp" value="10" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/.pio/libdeps/native/PubSubClient/src/PubSubClient.cpp</url>
|
||||
<line>468</line>
|
||||
<option name="timeStamp" value="11" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/mesh-pb-constants.cpp</url>
|
||||
<line>20</line>
|
||||
<option name="timeStamp" value="12" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
<watches-manager>
|
||||
<configuration name="CLion_Remote">
|
||||
<watch expression="radioConfig" language="ObjectiveC" />
|
||||
<watch expression="fromRadioScratch" language="ObjectiveC" />
|
||||
</configuration>
|
||||
</watches-manager>
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
<select />
|
||||
</component>
|
||||
</project>
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -77,6 +77,5 @@
|
||||
"--java_out=/tmp",
|
||||
"-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto"
|
||||
]
|
||||
},
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
}
|
||||
214
README.md
214
README.md
@@ -1,213 +1,5 @@
|
||||
# Meshtastic-device
|
||||
[](https://open.vscode.dev/meshtastic/Meshtastic-device)
|
||||
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
|
||||
|
||||
This is the device side code for the [meshtastic.org](https://www.meshtastic.org) project.
|
||||
|
||||

|
||||
|
||||
Meshtastic® is a project that lets you use
|
||||
inexpensive GPS mesh radios as an extensible, super long battery life mesh GPS communicator. These radios are great for hiking, skiing, paragliding -
|
||||
essentially any hobby where you don't have reliable internet access. Each member of your private mesh can always see the location and distance of all other
|
||||
members and any text messages sent to your group chat.
|
||||
|
||||
The radios automatically create a mesh to forward packets as needed, so everyone in the group can receive messages from even the furthest member. The radios
|
||||
will optionally work with your phone, but no phone is required.
|
||||
|
||||
Typical time between recharging the radios should be about eight days.
|
||||
|
||||
This project is is currently in beta-testing - if you have questions please [join our discussion forum](https://meshtastic.discourse.group/).
|
||||
|
||||
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the chat.
|
||||
|
||||
## Supported hardware
|
||||
|
||||
We currently support three models of radios.
|
||||
|
||||
- TTGO T-Beam (usually the recommended choice)
|
||||
- [T-Beam V1.1 w/ NEO-6M - special Meshtastic version](https://www.aliexpress.com/item/4001178678568.html) (Includes built-in OLED display and they have **preinstalled** the meshtastic software)
|
||||
- [T-Beam V1.1 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (slightly better GPS)
|
||||
- [T-Beam V1.1 w/ NEO-M8N /w SX1262](https://www.aliexpress.com/item/4001287221970.html) (slightly better GPS + LoRa)
|
||||
- board labels "TTGO T22_V1.1 20191212"
|
||||
- [T-Beam V0.7 w/ NEO-6M](https://www.aliexpress.com/item/4000574335430.html) (will work but **you must use the tbeam0.7 firmware ** - but the T-Beam V1.0 or later are better!)
|
||||
- board labels "TTGO T22_V07 20180711"
|
||||
- 3D printable cases
|
||||
- [T-Beam V0](https://www.thingiverse.com/thing:3773717) (GPS and LoRa antenna misaligned if GPS placed as pictured)
|
||||
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:3830711)
|
||||
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:4677388) (Mounting option for larger GPS antenna but LoRa antenna enclosed)
|
||||
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4587297) (GPS and LoRa antenna misaligned if GPS placed as pictured)
|
||||
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4589651)
|
||||
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4619981) (GPS and LoRa antenna misaligned if GPS placed as pictured)
|
||||
- Laser-cut cases
|
||||
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:4552771)
|
||||
|
||||
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
|
||||
- version 2.1
|
||||
- board labels "TTGO T3_V1.6 20180606"
|
||||
- 3D printable case
|
||||
- [TTGO LORA32 v1](https://www.thingiverse.com/thing:3385109)
|
||||
|
||||
- [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/) - No GPS
|
||||
- [Official Heltec case](https://www.aliexpress.com/item/4001050707951.html)
|
||||
- [3D Printable case](https://www.thingiverse.com/thing:3125854)
|
||||
|
||||
Note: The GPS and LoRa stock antennas should be placed in a way, that the GPS antenna faces the sky and the LoRa antenna radiates 360 degrees horizontally. For better GPS reception you might want to [upgrade the GPS antenna](https://meshtastic.discourse.group/t/the-importance-of-gps-antennas-and-request-to-3d-case-documentation-people/1505) and to properly align the antennas you might want to upgrade to a LoRa antenna that can be adjusted to radiate into the right directions.
|
||||
|
||||
**Make sure to get the frequency for your country**
|
||||
|
||||
- US/JP/AU/NZ/CA - 915MHz
|
||||
- CN - 470MHz
|
||||
- EU - 868MHz, 433MHz
|
||||
- full list of LoRa frequencies per region is available [here](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html)
|
||||
|
||||
Getting a version that includes a screen is optional, but highly recommended.
|
||||
|
||||
## Firmware Installation
|
||||
|
||||
Prebuilt binaries for the supported radios are available in our [releases](https://github.com/meshtastic/Meshtastic-esp32/releases). Your initial installation has to happen over USB from your Mac, Windows or Linux PC. Once our software is installed, all future software updates happen over bluetooth from your phone.
|
||||
|
||||
Be **very careful** to install the correct load for your board. In particular the popular 'T-BEAM' radio from TTGO is not called 'TTGO-Lora' (that is a different board). So don't install the 'TTGO-Lora' build on a TBEAM, it won't work correctly.
|
||||
|
||||
Please post comments on our [group chat](https://meshtastic.discourse.group/) if you have problems or successes.
|
||||
|
||||
### Installing from a GUI - Windows and Mac
|
||||
|
||||
1. Download and unzip the latest Meshtastic firmware [release](https://github.com/meshtastic/Meshtastic-esp32/releases).
|
||||
2. Download [ESPHome Flasher](https://github.com/esphome/esphome-flasher/releases) (either x86-32bit Windows or x64-64 bit Windows).
|
||||
3. Connect your radio to your USB port and open ESPHome Flasher.
|
||||
4. If your board is not showing under Serial Port then you likely need to install the drivers for the CP210X serial chip. In Windows you can check by searching “Device Manager” and ensuring the device is shown under “Ports”.
|
||||
5. If there is an error, download the drivers [here](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers), then unzip and run the Installer application.
|
||||
6. In ESPHome Flasher, refresh the serial ports and select your board.
|
||||
7. Browse to the previously downloaded firmware and select the correct firmware based on the board type, country and frequency.
|
||||
8. Select Flash ESP.
|
||||
9. Once complete, “Done! Flashing is complete!” will be shown.
|
||||
10. Debug messages sent from the Meshtastic device can be viewed with a terminal program such as [PuTTY](https://www.putty.org/) (Windows only). Within PuTTY, click “Serial”, enter the “Serial line” com port (can be found at step 4), enter “Speed” as 921600, then click “Open”.
|
||||
|
||||
### Installing from a commandline
|
||||
|
||||
These instructions currently require a few commmand lines, but it should be pretty straightforward.
|
||||
|
||||
1. Install "pip". Pip is the python package manager we use to get the esptool installer app. Instructions [here](https://www.makeuseof.com/tag/install-pip-for-python/). If you are using OS-X, see these [special instructions](docs/software/install-OSX.md).
|
||||
2. Run "pip install --upgrade esptool" to get esptool installed on your machine.
|
||||
3. Connect your radio to your USB port.
|
||||
4. Confirm that your device is talking to your PC by running "esptool.py chip_id". The Heltec build also works on the TTGO LORA32 radio. You should see something like:
|
||||
|
||||
```
|
||||
mydir$ esptool.py chip_id
|
||||
esptool.py v2.6
|
||||
Found 2 serial ports
|
||||
Serial port /dev/ttyUSB0
|
||||
Connecting....
|
||||
Detecting chip type... ESP32
|
||||
Chip is ESP32D0WDQ6 (revision 1)
|
||||
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
|
||||
MAC: 24:6f:28:b5:36:71
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Warning: ESP32 has no Chip ID. Reading MAC instead.
|
||||
MAC: 24:6f:28:b5:36:71
|
||||
Hard resetting via RTS pin...
|
||||
```
|
||||
|
||||
5. cd into the directory where the release zip file was expanded.
|
||||
6. Install the correct firmware for your board with `device-install.sh -f firmware-_board_-_country_.bin`.
|
||||
- Example: `./device-install.sh -f firmware-HELTEC-US-0.0.3.bin`.
|
||||
7. To update run `device-update.sh -f firmware-_board_-_country_.bin`
|
||||
- Example: `./device-update.sh -f firmware-HELTEC-US-0.0.3.bin`.
|
||||
|
||||
Note: If you have previously installed meshtastic, you don't need to run this full script instead just run `esptool.py --baud 921600 write_flash 0x10000 firmware-_board_-_country_-_version_.bin`. This will be faster, also all of your current preferences will be preserved.
|
||||
|
||||
You should see something like this:
|
||||
|
||||
```
|
||||
kevinh@kevin-server:~/development/meshtastic/meshtastic-esp32/release/latest$ ./device-install.sh firmware-TBEAM-US-0.1.8.bin
|
||||
Trying to flash firmware-TBEAM-US-0.1.8.bin, but first erasing and writing system information
|
||||
esptool.py v2.6
|
||||
Found 2 serial ports
|
||||
Serial port /dev/ttyUSB0
|
||||
Connecting........____
|
||||
Detecting chip type... ESP32
|
||||
Chip is ESP32D0WDQ6 (revision 1)
|
||||
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
|
||||
MAC: 24:6f:28:b2:01:6c
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Changing baud rate to 921600
|
||||
Changed.
|
||||
Erasing flash (this may take a while)...
|
||||
Chip erase completed successfully in 6.1s
|
||||
Hard resetting via RTS pin...
|
||||
esptool.py v2.6
|
||||
Found 2 serial ports
|
||||
Serial port /dev/ttyUSB0
|
||||
Connecting.......
|
||||
Detecting chip type... ESP32
|
||||
Chip is ESP32D0WDQ6 (revision 1)
|
||||
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
|
||||
MAC: 24:6f:28:b2:01:6c
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Changing baud rate to 921600
|
||||
Changed.
|
||||
Configuring flash size...
|
||||
Auto-detected Flash size: 4MB
|
||||
Flash params set to 0x0220
|
||||
Compressed 61440 bytes to 11950...
|
||||
Wrote 61440 bytes (11950 compressed) at 0x00001000 in 0.2 seconds (effective 3092.4 kbit/s)...
|
||||
Hash of data verified.
|
||||
|
||||
Leaving...
|
||||
Hard resetting via RTS pin...
|
||||
esptool.py v2.6
|
||||
Found 2 serial ports
|
||||
Serial port /dev/ttyUSB0
|
||||
Connecting.....
|
||||
Detecting chip type... ESP32
|
||||
Chip is ESP32D0WDQ6 (revision 1)
|
||||
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
|
||||
MAC: 24:6f:28:b2:01:6c
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Changing baud rate to 921600
|
||||
Changed.
|
||||
Configuring flash size...
|
||||
Auto-detected Flash size: 4MB
|
||||
Compressed 1223568 bytes to 678412...
|
||||
Wrote 1223568 bytes (678412 compressed) at 0x00010000 in 10.7 seconds (effective 912.0 kbit/s)...
|
||||
Hash of data verified.
|
||||
|
||||
Leaving...
|
||||
Hard resetting via RTS pin...
|
||||
```
|
||||
|
||||
7. The board will boot and show the Meshtastic logo.
|
||||
8. Please post a comment on our chat so we know if these instructions worked for you ;-). If you find bugs/have-questions post there also - we will be rapidly iterating over the next few weeks.
|
||||
|
||||
# Meshtastic Android app
|
||||
|
||||
The companion (optional) Meshtastic Android app is [here](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dgithub-dev-readme). You can also download it on Google Play.
|
||||
|
||||
# Python API
|
||||
|
||||
We offer a [python API](https://github.com/meshtastic/Meshtastic-python) that makes it easy to use these devices to provide mesh networking for your custom projects.
|
||||
|
||||
# Development
|
||||
|
||||
We'd love to have you join us on this merry little project. Please see our [development documents](./docs/software/sw-design.md) and [join us in our discussion forum](https://meshtastic.discourse.group/).
|
||||
|
||||
# Credits
|
||||
|
||||
This project is run by volunteers. We are a friendly group and welcome any contribution (code fixes, documentation, features, bug reports etc...). We try to be good about listing contributor names in release notes, but it has become unwieldy for the main-devs to keep updating the list below and we've neglected it too long. If you'd like your name included in this list please send a pull request to edit this README and simply add your line yourself. Thank you very much for your help!
|
||||
|
||||
- @astro-arphid: Added support for 433MHz radios in europe.
|
||||
- @claesg: Various documentation fixes and 3D print enclosures
|
||||
- @girtsf: Lots of improvements
|
||||
- @spattinson: Fixed interrupt handling for the AXP192 part
|
||||
|
||||
# IMPORTANT DISCLAIMERS AND FAQ
|
||||
|
||||
For a listing of currently missing features and a FAQ click [here](docs/faq.md).
|
||||
|
||||
Copyright 2019 Geeksville Industries, LLC. GPL V3 Licensed.
|
||||
For developer information and specific building instructions, please see the [developer doccumentation](https://meshtastic.org/docs/developers)
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py`
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
BOARDS_ESP32="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
|
||||
BOARDS_ESP32="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v2.0 heltec-v2.1 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
|
||||
BOARDS_NRF52="rak4631"
|
||||
BOARDS_NRF52="rak4631 t-echo"
|
||||
#BOARDS_NRF52=""
|
||||
|
||||
OUTDIR=release/latest
|
||||
|
||||
@@ -70,6 +72,9 @@ platformio lib update
|
||||
do_boards "$BOARDS_ESP32" "false"
|
||||
do_boards "$BOARDS_NRF52" "true"
|
||||
|
||||
pio run --environment native
|
||||
cp .pio/build/native/program $OUTDIR/bins/universal/meshtasticd_linux_amd64
|
||||
|
||||
echo "Building SPIFFS for ESP32 targets"
|
||||
pio run --environment tbeam -t buildfs
|
||||
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin
|
||||
@@ -91,11 +96,15 @@ Generated by bin/buildall.sh -->
|
||||
|
||||
<resources>
|
||||
<string name="cur_firmware_version" translatable="false">$VERSION</string>
|
||||
<string name="short_firmware_version" translatable="false">$SHORT_VERSION</string>
|
||||
</resources>
|
||||
XML
|
||||
|
||||
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
|
||||
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
|
||||
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh
|
||||
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
|
||||
echo Generating $ARCHIVEDIR/elfs-$VERSION.zip
|
||||
rm -f $ARCHIVEDIR/elfs-$VERSION.zip
|
||||
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*
|
||||
|
||||
echo BUILT ALL
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
import configparser
|
||||
import sys
|
||||
from readprops import readProps
|
||||
|
||||
|
||||
verStr = readProps('version.properties')
|
||||
print(f"{verStr}")
|
||||
verObj = readProps('version.properties')
|
||||
propName = sys.argv[1]
|
||||
print(f"{verObj[propName]}")
|
||||
|
||||
42
bin/device-install.bat
Normal file
42
bin/device-install.bat
Normal file
@@ -0,0 +1,42 @@
|
||||
@ECHO OFF
|
||||
|
||||
set PYTHON=python
|
||||
|
||||
goto GETOPTS
|
||||
:HELP
|
||||
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME]
|
||||
echo Flash image file to device, but first erasing and writing system information
|
||||
echo.
|
||||
echo -h Display this help and exit
|
||||
echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||
echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%)
|
||||
echo -f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
goto EOF
|
||||
|
||||
:GETOPTS
|
||||
if /I "%1"=="-h" goto HELP
|
||||
if /I "%1"=="--help" goto HELP
|
||||
if /I "%1"=="-F" set "FILENAME=%2" & SHIFT
|
||||
if /I "%1"=="-p" set ESPTOOL_PORT=%2 & SHIFT
|
||||
if /I "%1"=="-P" set PYTHON=%2 & SHIFT
|
||||
SHIFT
|
||||
IF NOT "__%1__"=="____" goto GETOPTS
|
||||
|
||||
IF "__%FILENAME%__" == "____" (
|
||||
echo "Missing FILENAME"
|
||||
goto HELP
|
||||
)
|
||||
IF EXIST %FILENAME% (
|
||||
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
||||
%PYTHON% -m esptool --baud 921600 erase_flash
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x1000 system-info.bin
|
||||
for %%f in (spiffs-*.bin) do (
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x00390000 %%f
|
||||
)
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME%
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
)
|
||||
|
||||
:EOF
|
||||
39
bin/device-update.bat
Normal file
39
bin/device-update.bat
Normal file
@@ -0,0 +1,39 @@
|
||||
@ECHO OFF
|
||||
|
||||
set PYTHON=python
|
||||
|
||||
goto GETOPTS
|
||||
:HELP
|
||||
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME]
|
||||
echo Flash image file to device, leave existing system intact.
|
||||
echo.
|
||||
echo -h Display this help and exit
|
||||
echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||
echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%)
|
||||
echo -f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
goto EOF
|
||||
|
||||
:GETOPTS
|
||||
if /I "%1"=="-h" goto HELP
|
||||
if /I "%1"=="--help" goto HELP
|
||||
if /I "%1"=="-F" set "FILENAME=%2" & SHIFT
|
||||
if /I "%1"=="-p" set ESPTOOL_PORT=%2 & SHIFT
|
||||
if /I "%1"=="-P" set PYTHON=%2 & SHIFT
|
||||
SHIFT
|
||||
IF NOT "__%1__"=="____" goto GETOPTS
|
||||
|
||||
IF "__%FILENAME%__" == "____" (
|
||||
echo "Missing FILENAME"
|
||||
goto HELP
|
||||
)
|
||||
IF EXIST %FILENAME% (
|
||||
echo Trying to flash update %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%"
|
||||
goto HELP
|
||||
)
|
||||
|
||||
:EOF
|
||||
@@ -9,11 +9,12 @@ from readprops import readProps
|
||||
Import("projenv")
|
||||
|
||||
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
||||
verStr = readProps(prefsLoc)
|
||||
print("Using meshtastic platform-custom.py, firmare version " + verStr)
|
||||
verObj = readProps(prefsLoc)
|
||||
print("Using meshtastic platform-custom.py, firmare version " + verObj['long'])
|
||||
# print("path is" + ','.join(sys.path))
|
||||
|
||||
# General options that are passed to the C and C++ compilers
|
||||
projenv.Append(CCFLAGS=[
|
||||
"-DAPP_VERSION=" + verStr
|
||||
"-DAPP_VERSION=" + verObj['long'],
|
||||
"-DAPP_VERSION_SHORT=" + verObj['short']
|
||||
])
|
||||
|
||||
11
bin/promote-release.sh
Executable file
11
bin/promote-release.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
set -e
|
||||
|
||||
echo "This script is only for developers who are publishing new builds on github. Most users don't need it"
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
|
||||
# Must have a V prefix to trigger github
|
||||
git tag "v${VERSION}"
|
||||
git push root "v${VERSION}" # push the tag
|
||||
|
||||
echo "Tag ${VERSION} pushed to github, github actions should now be building the draft release. If it seems good, click to publish it"
|
||||
@@ -12,6 +12,8 @@ def readProps(prefsLoc):
|
||||
config = configparser.RawConfigParser()
|
||||
config.read(prefsLoc)
|
||||
version = dict(config.items('VERSION'))
|
||||
verObj = dict(short = "{}.{}.{}".format(version["major"], version["minor"], version["build"]),
|
||||
long = "unset")
|
||||
|
||||
# Try to find current build SHA if if the workspace is clean. This could fail if git is not installed
|
||||
try:
|
||||
@@ -23,14 +25,13 @@ def readProps(prefsLoc):
|
||||
if isDirty:
|
||||
# short for 'dirty', we want to keep our verstrings source for protobuf reasons
|
||||
suffix = sha + "-d"
|
||||
verStr = "{}.{}.{}.{}".format(
|
||||
verObj['long'] = "{}.{}.{}.{}".format(
|
||||
version["major"], version["minor"], version["build"], suffix)
|
||||
except:
|
||||
# print("Unexpected error:", sys.exc_info()[0])
|
||||
# traceback.print_exc()
|
||||
verStr = "{}.{}.{}".format(
|
||||
version["major"], version["minor"], version["build"])
|
||||
verObj['long'] = verObj['short']
|
||||
|
||||
# print("firmare version " + verStr)
|
||||
return verStr
|
||||
return verObj
|
||||
# print("path is" + ','.join(sys.path))
|
||||
|
||||
@@ -10,6 +10,6 @@ echo "prebuilt binaries for your computer into nanopb-0.4.4"
|
||||
cd proto
|
||||
../nanopb-0.4.4/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../proto *.proto
|
||||
|
||||
echo "Regenerating protobuf documentation - if you see an error message"
|
||||
echo "you can ignore it unless doing a new protobuf release to github."
|
||||
bin/regen-docs.sh
|
||||
#echo "Regenerating protobuf documentation - if you see an error message"
|
||||
#echo "you can ignore it unless doing a new protobuf release to github."
|
||||
#bin/regen-docs.sh
|
||||
9
bin/test-simulator.sh
Executable file
9
bin/test-simulator.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
set -e
|
||||
|
||||
echo "Starting simulator"
|
||||
.pio/build/native/program &
|
||||
sleep 20 # 5 seconds was not enough
|
||||
|
||||
echo "Simulator started, launching python test..."
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
set -e
|
||||
|
||||
echo "Converting to uf2 for NRF52 Adafruit bootloader"
|
||||
bin/uf2conv.py .pio/build/rak4631/firmware.hex -f 0xADA52840
|
||||
echo "building for t-echo"
|
||||
pio run --environment t-echo
|
||||
|
||||
echo "Converting to uf2 for NRF52 Adafruit bootloader - double tap on the reset button to force bootloader entry"
|
||||
bin/uf2conv.py .pio/build/t-echo/firmware.hex -f 0xADA52840
|
||||
cp flash.uf2 /media/kevinh/FTH*BOOT/
|
||||
|
||||
5
bin/upload-to-rak4631.sh
Executable file
5
bin/upload-to-rak4631.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
set -e
|
||||
|
||||
echo "Converting to uf2 for NRF52 Adafruit bootloader"
|
||||
bin/uf2conv.py .pio/build/rak4631/firmware.hex -f 0xADA52840
|
||||
cp flash.uf2 /media/kevinh/FTH*BOOT/
|
||||
@@ -15,7 +15,7 @@
|
||||
],
|
||||
"usb_product": "TTGO_eink",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "eink",
|
||||
"variant": "t-echo",
|
||||
"variants_dir": "variants",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
@@ -44,17 +44,20 @@
|
||||
"arduino"
|
||||
],
|
||||
"name": "TTGO eink (Adafruit BSP)",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"protocol": "jlink",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"stlink"
|
||||
]
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"stlink"
|
||||
],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "FIXME",
|
||||
"vendor": "TTGO"
|
||||
@@ -2,22 +2,21 @@
|
||||
|
||||
You probably don't care about this section - skip to the next one.
|
||||
|
||||
## before next release
|
||||
|
||||
* @havealoha fixedposition not working
|
||||
* pine64 lora module
|
||||
* merge https://meshtastic.discourse.group/t/spanish-translation-update/2986/5
|
||||
* nrf52 USB is unreliable while sleeping?
|
||||
* @luxonn reports that after a while the android app stops showing new messages
|
||||
* nrf52 shows as "sleeping" in android app? (but led is blinking)
|
||||
* usb lora dongle from pine64, add end user instructions
|
||||
* measure rak4630 power draw and turn off power for GPS most of the time. We should be able to run on the small solar panel.
|
||||
* turn on watchdog reset if app hangs on nrf52 or esp32
|
||||
* pine64 solar boards
|
||||
* for the matrix gateway? recommended by @sam-uk https://github.com/matrix-org/coap-proxy
|
||||
* figure our wss for mqtt.meshtastic - use cloudflare? 2052 ws, 2053 crypt
|
||||
* ask for vercel access
|
||||
* fix heltec battery scaling
|
||||
* check android 1.2.20 usage, possibly release to general
|
||||
* release android APK
|
||||
|
||||
* add rak4600 support (with rf95 radio and limited ram)
|
||||
|
||||
* Switch to use https://github.com/adafruit/Adafruit_nRF52_Arduino.git when available (see arduino code for examples)
|
||||
* finish plan for riot.im
|
||||
* turn on setTx(timeout) and state = setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT); in sx1262 code
|
||||
* NO add rak4600 support (with rf95 radio and limited ram)
|
||||
* store esp32 crashes to flash (and 64KB coredump partition) - https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/core_dump.html
|
||||
* If more nodes appear than the nodedb can hold, delete oldest entries from DB
|
||||
* send debug info 'in-band'
|
||||
* DONE @luxonn reports that after a while the android app stops showing new messages
|
||||
* DONE release android APK - fix recent 1.2.28 crash report
|
||||
* DONE remote admin busted?
|
||||
* DONE check android code - @havealoha comments about odd sleep behavior
|
||||
* ABANDONED test github actions locally on linux
|
||||
@@ -28,7 +27,6 @@ You probably don't care about this section - skip to the next one.
|
||||
* DONE tcp stream problem in python+pordtuino, server thinks client dropped when client DID NOT DROP
|
||||
* DONE TCP mode for android, localhost is at 10.0.2.2
|
||||
* DONE make sure USB still works in android
|
||||
* add portduino builds to zip
|
||||
* add license to portduino and make announcement
|
||||
* DONE naks are being dropped (though enqueuedLocal) sometimes before phone/PC gets them
|
||||
* DONE have android fill in if local GPS has poor signal
|
||||
|
||||
23
geeksville-private/bl602.md
Normal file
23
geeksville-private/bl602.md
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
* nutcracker https://www.pine64.org/2020/10/28/nutcracker-challenge-blob-free-wifi-ble/
|
||||
* https://github.com/pine64/bl_iot_sdk
|
||||
* https://github.com/pine64/bl602-docs / https://pine64.github.io/bl602-docs/
|
||||
* https://github.com/pine64/ArduinoCore-bouffalo
|
||||
|
||||
|
||||
cd ~/packages
|
||||
git clone --recursive https://github.com/pine64/bl_iot_sdk
|
||||
|
||||
https://github.com/spacemeowx2/blflash/releases
|
||||
|
||||
|
||||
# FIXME or BL604
|
||||
cd bl_iot_sdk
|
||||
export BL60X_SDK_PATH=/home/kevinh/packages/bl_iot_sdk
|
||||
export CONFIG_CHIP_NAME=BL602
|
||||
cd customer_app/bl602_boot2
|
||||
make
|
||||
|
||||
* todo run hello world on hardware (check for bl604 vs bl602 first)
|
||||
* build/run in the crummy arduino environment
|
||||
* build in platformio
|
||||
51
geeksville-private/pine64.md
Normal file
51
geeksville-private/pine64.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Notes on the pine64 lora board
|
||||
|
||||
like before but sx1262 based?
|
||||
|
||||
Since both DIO3 and DIO2 not apply to PINE64 LoRa situation, I will wire SX1262 INT [DIO1] pin, contact to CS341F pin 7 INT# and pin 5.
|
||||
|
||||
FIX ch341 GPIO access from linux
|
||||
RF95 packet RX seems busted FIX FIRST
|
||||
|
||||
USE ch341 devboard if needed
|
||||
|
||||
SX1262 BUSY seems to come out on pin 15 of the RFM90 HOPE module. The 'footprint' seems rotated on the pine64 board schematic and that becomes pin 7 on U4 which is "DIO5" on that schematic. Which goes to pin 8 on the CH341F, which that datasheet calls "IN3"
|
||||
|
||||
FIXME - see if possible to read BUSY from "IN3"?
|
||||
|
||||
on a ch341a
|
||||
* - Pin 15 (D0/CS0 ) as input/output/CS (CH341_PIN_MODE_IN/CH341_PIN_MODE_OUT/CH341_PIN_MODE_CS) (confirm hooked to CS)
|
||||
* - Pin 16 (D1/CS1 ) as input/output/CS (CH341_PIN_MODE_IN/CH341_PIN_MODE_OUT/CH341_PIN_MODE_CS)
|
||||
* - Pin 17 (D2/CS2 ) as input/output/CS (CH341_PIN_MODE_IN/CH341_PIN_MODE_OUT/CH341_PIN_MODE_CS)
|
||||
* - Pin 19 (D4/DOUT2) as input/output (CH341_PIN_MODE_IN/CH341_PIN_MODE_OUT) / gpio4 in linux driver / (FIXME: confirm hooked to IRQ also?)
|
||||
* - Pin 21 (D6/DIN2 ) as input (CH341_PIN_MODE_IN) / called RTS when in UART mode
|
||||
|
||||
## ch341-driver
|
||||
|
||||
driver busted in 5.11 kernels (rf95 init fails). 5.8.0 is okay, 5.8.18 is okay. fails on 5.10.31, 5.9.16 is okay. Therefore breakage happened in 5.10 kernels! Possibly not really breakage, possibly just sloppy caching or something that is more easily caught with modern threading.
|
||||
|
||||
cs_change is not being set on the way into the driver!
|
||||
|
||||
## gpio
|
||||
|
||||
the new GPIO interface https://embeddedbits.org/new-linux-kernel-gpio-user-space-interface/
|
||||
|
||||
~/development/meshtastic/meshtastic-esp32$ gpiodetect
|
||||
gpiochip0 [INT34BB:00] (312 lines)
|
||||
gpiochip1 [ch341] (2 lines)
|
||||
~/development/meshtastic/meshtastic-esp32$ gpioinfo 1
|
||||
gpiochip1 - 2 lines:
|
||||
line 0: "gpio4" unused input active-high
|
||||
line 1: "gpio5" unused input active-high
|
||||
gpiofind gpio4
|
||||
gpiochip1 0
|
||||
|
||||
DO NOT "apt install libgpiod-dev" It doesn't work with kernels newer than about 5.8. Instead build and install from source: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/
|
||||
|
||||
## Send in patch
|
||||
Fix drivers/spi/spi.c transfer_once
|
||||
|
||||
read about spi: https://elinux.org/images/2/20/Whats_going_on_with_SPI--mark_brown.pdf
|
||||
|
||||
https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html
|
||||
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
||||
7
geeksville-private/windows-build-instructions.md
Normal file
7
geeksville-private/windows-build-instructions.md
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
* install python
|
||||
* install git (including git-bash)
|
||||
* install platformio
|
||||
* install vscode
|
||||
* install https://sourceforge.net/projects/mingw-w64/ (for windows gcc/g++) - you'll need to add the bin directory to your PATH
|
||||
113
platformio.ini
113
platformio.ini
@@ -9,14 +9,14 @@
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = tbeam
|
||||
;default_envs = tbeam
|
||||
;default_envs = tbeam0.7
|
||||
;default_envs = heltec
|
||||
;default_envs = heltec-v2.0
|
||||
;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 = t-echo
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = rak4631
|
||||
@@ -70,9 +70,9 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
|
||||
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
|
||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||
https://github.com/meshtastic/arduino-fsm.git#829e967b8a95c094f73c60ef8dacfe66eae38940
|
||||
https://github.com/meshtastic/arduino-fsm.git
|
||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||
https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a
|
||||
https://github.com/meshtastic/RadioLib.git#80ed10d689a0568782c5bd152906b0f97d2bce93
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
|
||||
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||
@@ -88,7 +88,8 @@ framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
|
||||
build_flags = ${env.build_flags} -Os
|
||||
build_flags = ${env.build_flags} -Os
|
||||
# -DRADIOLIB_GODMODE
|
||||
|
||||
src_filter = ${env.src_filter} -<portduino/>
|
||||
|
||||
@@ -150,10 +151,19 @@ board = ttgo-t-beam
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TBEAM_V07
|
||||
|
||||
[env:heltec]
|
||||
[env:heltec-v2.0]
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
extends = esp32_base
|
||||
board = heltec_wifi_lora_32_V2
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D HELTEC_V2_0
|
||||
|
||||
[env:heltec-v2.1]
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
extends = esp32_base
|
||||
board = heltec_wifi_lora_32_V2
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D HELTEC_V2_1
|
||||
|
||||
[env:tlora-v1]
|
||||
extends = esp32_base
|
||||
@@ -183,13 +193,13 @@ build_flags =
|
||||
; The Heltec Cubecell plus
|
||||
; IMPORTANT NOTE: This target doesn't yet work and probably won't ever work. I'm keeping it around for now.
|
||||
; For more details see my post in the forum.
|
||||
[env:cubecellplus]
|
||||
platform = https://github.com/HelTecAutomation/platform-asrmicro650x.git ; we use top-of-tree because stable version has too many bugs - asrmicro650x
|
||||
board = cubecell_board_plus
|
||||
;[env:cubecellplus]
|
||||
;platform = https://github.com/HelTecAutomation/platform-asrmicro650x.git ; we use top-of-tree because stable version has too many bugs - asrmicro650x
|
||||
;board = cubecell_board_plus
|
||||
; FIXME, bug in cubecell arduino - they are supposed to set ARDUINO
|
||||
build_flags = ${arduino_base.build_flags} -DARDUINO=100 -Isrc/cubecell
|
||||
src_filter =
|
||||
${arduino_base.src_filter} -<esp32/> -<nrf52/>
|
||||
;build_flags = ${arduino_base.build_flags} -DARDUINO=100 -Isrc/cubecell
|
||||
;src_filter =
|
||||
; ${arduino_base.src_filter} -<esp32/> -<nrf52/>
|
||||
|
||||
; Common settings for NRF52 based targets
|
||||
[nrf52_base]
|
||||
@@ -208,10 +218,10 @@ src_filter =
|
||||
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32> -<mqtt/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
monitor_port = /dev/ttyACM1
|
||||
; monitor_port = /dev/ttyACM1
|
||||
|
||||
# we pass in options to jlink so it can understand freertos (note: we don't use "jlink" as the tool)
|
||||
debug_tool = jlink
|
||||
;debug_tool = jlink
|
||||
debug_port = :2331
|
||||
# Note: the ARGUMENTS MUST BE on multiple lines. Otherwise platformio/commands/debug/helpers.py misparses everything into the "executable"
|
||||
# attribute and leaves "arguments" empty
|
||||
@@ -245,9 +255,12 @@ debug_init_break =
|
||||
[nrf52840_base]
|
||||
; Common base class for all nrf52840 based targets
|
||||
extends = nrf52_base
|
||||
; was -DTINY_USB
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
Adafruit nRFCrypto
|
||||
# Adafruit TinyUSB Arduino
|
||||
# add Adafruit nRFCrypto platform IO automated scan is broken
|
||||
|
||||
[env:lora_isp4520]
|
||||
@@ -305,12 +318,13 @@ extends = nrf52840_base
|
||||
board = wiscore_rak4631
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/WisCore_RAK4631_Board
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
;upload_protocol = jlink
|
||||
|
||||
; Note, this board is not yet supported! It will not work without futher development.
|
||||
; THIS IS UNTESTED (I don't have this board), but other developers can use it as a starting point
|
||||
[env:rak4600]
|
||||
extends = nrf52_base
|
||||
@@ -340,32 +354,36 @@ lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
|
||||
; First prototype eink/nrf52840/sx1262 device
|
||||
[env:eink]
|
||||
[env:t-echo]
|
||||
extends = nrf52840_base
|
||||
board = eink
|
||||
board = t-echo
|
||||
debug_tool = jlink
|
||||
upload_protocol = jlink
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/eink
|
||||
-DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/eink>
|
||||
# define build flags for the TFT_eSPI library - NOTE: WE NOT LONGER USE TFT_eSPI, it was for an earlier version of the TTGO eink screens
|
||||
# -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/t-echo>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
https://github.com/geeksville/EPD_Libraries.git
|
||||
TFT_eSPI
|
||||
https://github.com/geeksville/GxEPD2.git
|
||||
adafruit/Adafruit BusIO
|
||||
;upload_protocol = fs
|
||||
|
||||
; First prototype eink/nrf52840/sx1262 device
|
||||
[env:eink0.1]
|
||||
extends = nrf52840_base
|
||||
board = eink0.1
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
|
||||
-DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
https://github.com/geeksville/EPD_Libraries.git
|
||||
TFT_eSPI
|
||||
; First prototype eink/nrf52840/sx1262 device (removed from build because didn't ship in quantity)
|
||||
;[env:eink0.1]
|
||||
;extends = nrf52840_base
|
||||
;board = eink0.1
|
||||
;# add our variants files to the include and src paths
|
||||
;# define build flags for the TFT_eSPI library
|
||||
;build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
|
||||
; -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
;src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
|
||||
;lib_deps =
|
||||
; ${nrf52840_base.lib_deps}
|
||||
; https://github.com/geeksville/EPD_Libraries.git
|
||||
; TFT_eSPI
|
||||
|
||||
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
|
||||
[env:lora-relay-v1]
|
||||
@@ -373,7 +391,7 @@ extends = nrf52840_base
|
||||
board = lora-relay-v1
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v1
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1
|
||||
-DUSER_SETUP_LOADED
|
||||
-DTFT_WIDTH=80
|
||||
-DTFT_HEIGHT=160
|
||||
@@ -395,7 +413,7 @@ extends = nrf52840_base
|
||||
board = lora-relay-v2
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v2
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2
|
||||
-DUSER_SETUP_LOADED
|
||||
-DTFT_WIDTH=80
|
||||
-DTFT_HEIGHT=160
|
||||
@@ -413,13 +431,24 @@ lib_deps =
|
||||
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
|
||||
TFT_eSPI
|
||||
|
||||
; The Portduino based sim environment on top of linux
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[env:native]
|
||||
platform = https://github.com/geeksville/platform-native.git
|
||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
||||
build_flags = ${arduino_base.build_flags} -O0
|
||||
build_flags = ${arduino_base.build_flags} -O0
|
||||
framework = arduino
|
||||
board = native
|
||||
board = cross_platform
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
rweather/Crypto
|
||||
|
||||
; The Portduino based sim environment on top of a linux OS and touching linux hardware devices
|
||||
[env:linux]
|
||||
platform = https://github.com/geeksville/platform-native.git
|
||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
||||
build_flags = ${arduino_base.build_flags} -O0 -lgpiod
|
||||
framework = arduino
|
||||
board = linux_hardware
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
rweather/Crypto
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 157f9891dd...f5b3d0643b
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "BluetoothCommon.h"
|
||||
|
||||
// NRF52 wants these constants as byte arrays
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "FSCommon.h"
|
||||
|
||||
void fsInit()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "OSTimer.h"
|
||||
#include "configuration.h"
|
||||
#include "OSTimer.h"
|
||||
|
||||
/**
|
||||
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
#include "configuration.h"
|
||||
#include "Observer.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "power.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
@@ -42,6 +43,7 @@ Power *power;
|
||||
|
||||
using namespace meshtastic;
|
||||
|
||||
#ifndef AREF_VOLTAGE
|
||||
#if defined(NRF52_SERIES)
|
||||
/*
|
||||
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
|
||||
@@ -56,6 +58,7 @@ using namespace meshtastic;
|
||||
#else
|
||||
#define AREF_VOLTAGE 3.3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If this board has a battery level sensor, set this to a valid implementation
|
||||
@@ -79,10 +82,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
if (v < noBatVolt)
|
||||
return -1; // If voltage is super low assume no battery installed
|
||||
|
||||
#ifndef NRF52_SERIES
|
||||
// This does not work on a RAK4631 with battery connected
|
||||
if (v > chargingVolt)
|
||||
return 0; // While charging we can't report % full on the battery
|
||||
#endif
|
||||
|
||||
return 100 * (v - emptyVolt) / (fullVolt - emptyVolt);
|
||||
return clamp((int)(100 * (v - emptyVolt) / (fullVolt - emptyVolt)), 0, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,8 +107,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
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));
|
||||
float scaled;
|
||||
#ifndef VBAT_RAW_TO_SCALED
|
||||
scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
|
||||
#else
|
||||
scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h
|
||||
#endif
|
||||
// DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
||||
last_read_value = scaled;
|
||||
return scaled;
|
||||
} else {
|
||||
@@ -120,7 +131,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
virtual bool isVBUSPlug() { return getBattVoltage() > 1000 * chargingVolt; }
|
||||
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
|
||||
|
||||
/// Assume charging if we have a battery and external power is connected.
|
||||
/// we can't be smart enough to say 'full'?
|
||||
@@ -129,17 +140,21 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
private:
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
const float fullVolt = 4200, emptyVolt = 3270, chargingVolt = 4210, noBatVolt = 2100;
|
||||
|
||||
/// For heltecs with no battery connected, the measured voltage is 2204, so raising to 2230 from 2100
|
||||
const float fullVolt = 4200, emptyVolt = 3270, chargingVolt = 4210, noBatVolt = 2230;
|
||||
float last_read_value = 0.0;
|
||||
uint32_t last_read_time_ms = 0;
|
||||
} analogLevel;
|
||||
};
|
||||
|
||||
AnalogBatteryLevel analogLevel;
|
||||
|
||||
Power::Power() : OSThread("Power") {}
|
||||
|
||||
bool Power::analogInit()
|
||||
{
|
||||
#ifdef BATTERY_PIN
|
||||
DEBUG_MSG("Using analog input for battery level\n");
|
||||
DEBUG_MSG("Using analog input %d for battery level\n", BATTERY_PIN);
|
||||
|
||||
// disable any internal pullups
|
||||
pinMode(BATTERY_PIN, INPUT);
|
||||
@@ -149,11 +164,19 @@ bool Power::analogInit()
|
||||
adcAttachPin(BATTERY_PIN);
|
||||
#endif
|
||||
#ifdef NRF52_SERIES
|
||||
#ifdef VBAT_AR_INTERNAL
|
||||
analogReference(VBAT_AR_INTERNAL);
|
||||
#else
|
||||
analogReference(AR_INTERNAL); // 3.6V
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_SENSE_RESOLUTION_BITS
|
||||
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
||||
#endif
|
||||
|
||||
// adcStart(BATTERY_PIN);
|
||||
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
|
||||
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
|
||||
batteryLevel = &analogLevel;
|
||||
return true;
|
||||
#else
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "configuration.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "sleep.h"
|
||||
@@ -28,6 +27,7 @@ static bool isPowered()
|
||||
|
||||
static void sdsEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: SDS\n");
|
||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||
doDeepSleep(getPref_sds_secs() * 1000LL);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ static void lsEnter()
|
||||
screen->setOn(false);
|
||||
secsSlept = 0; // How long have we been sleeping this time
|
||||
|
||||
DEBUG_MSG("lsEnter end\n");
|
||||
// DEBUG_MSG("lsEnter end\n");
|
||||
}
|
||||
|
||||
static void lsIdle()
|
||||
@@ -113,6 +113,7 @@ static void lsIdle()
|
||||
|
||||
static void lsExit()
|
||||
{
|
||||
DEBUG_MSG("Exit state: LS\n");
|
||||
// setGPSPower(true); // restore GPS power
|
||||
if (gps)
|
||||
gps->forceWake(true);
|
||||
@@ -120,6 +121,7 @@ static void lsExit()
|
||||
|
||||
static void nbEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: NB\n");
|
||||
screen->setOn(false);
|
||||
setBluetoothEnable(false);
|
||||
|
||||
@@ -134,6 +136,7 @@ static void darkEnter()
|
||||
|
||||
static void serialEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: SERIAL\n");
|
||||
setBluetoothEnable(false);
|
||||
screen->setOn(true);
|
||||
screen->print("Serial connected\n");
|
||||
@@ -146,6 +149,7 @@ static void serialExit()
|
||||
|
||||
static void powerEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: POWER\n");
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||
DEBUG_MSG("Loss of power in Powered\n");
|
||||
@@ -175,6 +179,7 @@ static void powerExit()
|
||||
|
||||
static void onEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: ON\n");
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
|
||||
@@ -203,7 +208,9 @@ static void screenPress()
|
||||
screen->onPress();
|
||||
}
|
||||
|
||||
static void bootEnter() {}
|
||||
static void bootEnter() {
|
||||
DEBUG_MSG("Enter state: BOOT\n");
|
||||
}
|
||||
|
||||
State stateSDS(sdsEnter, NULL, NULL, "SDS");
|
||||
State stateLS(lsEnter, lsIdle, lsExit, "LS");
|
||||
@@ -227,10 +234,9 @@ void PowerFSM_setup()
|
||||
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
|
||||
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
||||
|
||||
// Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB or dark and
|
||||
// then it handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet");
|
||||
|
||||
powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake");
|
||||
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from light sleep we _always_ transition to NB or dark and
|
||||
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, exiting light sleep");
|
||||
powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake");
|
||||
|
||||
// Handle press events - note: we ignore button presses when in API mode
|
||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
|
||||
@@ -254,6 +260,9 @@ void PowerFSM_setup()
|
||||
|
||||
// if we are a router we don't turn the screen on for these things
|
||||
if (!isRouter) {
|
||||
// if any packet destined for phone arrives, turn on bluetooth at least
|
||||
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
|
||||
|
||||
// show the latest node when we get a new node db update
|
||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
|
||||
@@ -293,13 +302,13 @@ void PowerFSM_setup()
|
||||
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");
|
||||
|
||||
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
|
||||
State *lowPowerState = &stateLS;
|
||||
|
||||
uint32_t meshSds = 0;
|
||||
|
||||
#ifndef NRF52_SERIES
|
||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||
|
||||
@@ -308,11 +317,12 @@ void PowerFSM_setup()
|
||||
|
||||
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
|
||||
meshSds = getPref_mesh_sds_timeout_secs();
|
||||
#else
|
||||
lowPowerState = &stateDARK;
|
||||
meshSds = UINT32_MAX; //Workaround for now: Don't go into deep sleep on the RAK4631
|
||||
#endif
|
||||
|
||||
auto meshSds = getPref_mesh_sds_timeout_secs();
|
||||
if (meshSds != UINT32_MAX)
|
||||
powerFSM.add_timed_transition(lowPowerState, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
|
||||
// removing for now, because some users don't even have phones
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define EVENT_PRESS 1
|
||||
#define EVENT_WAKE_TIMER 2
|
||||
#define EVENT_RECEIVED_PACKET 3
|
||||
// #define EVENT_RECEIVED_PACKET 3
|
||||
#define EVENT_PACKET_FOR_PHONE 4
|
||||
#define EVENT_RECEIVED_TEXT_MSG 5
|
||||
// #define EVENT_BOOT 6 // now done with a timed transition
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "configuration.h"
|
||||
#include "RedirectablePrint.h"
|
||||
#include "RTC.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
// #include "wifi/WiFiServerAPI.h"
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <cstring>
|
||||
|
||||
/**
|
||||
* A printer that doesn't go anywhere
|
||||
@@ -24,6 +26,10 @@ size_t RedirectablePrint::write(uint8_t c)
|
||||
SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c);
|
||||
#endif
|
||||
|
||||
// FIXME - clean this up, the whole relationship of this class to SerialConsole to TCP/bluetooth debug log output is kinda messed up. But for now, just have this hack to
|
||||
// optionally send chars to TCP also
|
||||
//WiFiServerPort::debugOut(c);
|
||||
|
||||
dest->write(c);
|
||||
return 1; // We always claim one was written, rather than trusting what the
|
||||
// serial port said (which could be zero)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "SPILock.h"
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "configuration.h"
|
||||
#include "SerialConsole.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define Port Serial
|
||||
|
||||
@@ -32,6 +31,13 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
emitRebooted();
|
||||
}
|
||||
|
||||
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
bool SerialConsole::checkIsConnected()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
return (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL;
|
||||
}
|
||||
|
||||
/**
|
||||
* we override this to notice when we've received a protobuf over the serial
|
||||
* stream. Then we shunt off debug serial output.
|
||||
@@ -46,14 +52,3 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||
return StreamAPI::handleToRadio(buf, len);
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void SerialConsole::onConnectionChanged(bool connected)
|
||||
{
|
||||
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
// FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't
|
||||
// received a packet in a while
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,9 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected();
|
||||
};
|
||||
|
||||
// A simple wrapper to allow non class aware code write to the console
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "configuration.h"
|
||||
#include "airtime.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define periodsToLog 48
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "concurrency/BinarySemaphoreFreeRTOS.h"
|
||||
#include "configuration.h"
|
||||
#include "concurrency/BinarySemaphoreFreeRTOS.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "concurrency/BinarySemaphorePosix.h"
|
||||
#include "configuration.h"
|
||||
#include "concurrency/BinarySemaphorePosix.h"
|
||||
|
||||
#ifndef HAS_FREE_RTOS
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "concurrency/InterruptableDelay.h"
|
||||
#include "configuration.h"
|
||||
#include "concurrency/InterruptableDelay.h"
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "Lock.h"
|
||||
#include <cassert>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "LockGuard.h"
|
||||
|
||||
namespace concurrency {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "NotifiedWorkerThread.h"
|
||||
#include "configuration.h"
|
||||
#include "NotifiedWorkerThread.h"
|
||||
#include "main.h"
|
||||
#include <assert.h>
|
||||
|
||||
@@ -72,14 +72,21 @@ bool NotifiedWorkerThread::notifyLater(uint32_t delay, uint32_t v, bool overwrit
|
||||
return didIt;
|
||||
}
|
||||
|
||||
int32_t NotifiedWorkerThread::runOnce()
|
||||
void NotifiedWorkerThread::checkNotification()
|
||||
{
|
||||
auto n = notification;
|
||||
enabled = false; // Only run once per notification
|
||||
notification = 0; // clear notification
|
||||
if (n) {
|
||||
onNotify(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t NotifiedWorkerThread::runOnce()
|
||||
{
|
||||
enabled = false; // Only run once per notification
|
||||
checkNotification();
|
||||
|
||||
return RUN_SAME;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,14 @@ class NotifiedWorkerThread : public OSThread
|
||||
protected:
|
||||
virtual void onNotify(uint32_t notification) = 0;
|
||||
|
||||
/// just calls checkNotification()
|
||||
virtual int32_t runOnce();
|
||||
|
||||
/// Sometimes we might want to check notifications independently of when our thread was getting woken up (i.e. if we are about to change
|
||||
/// radio transmit/receive modes we want to handle any pending interrupts first). You can call this method and if any notifications are currently
|
||||
/// pending they will be handled immediately.
|
||||
void checkNotification();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Notify this thread so it can run
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "OSThread.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace concurrency
|
||||
|
||||
@@ -227,8 +227,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define GPS_TX_PIN 15
|
||||
|
||||
#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 HardwareModel_HELTEC
|
||||
|
||||
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
|
||||
// Tested on Neo6m module.
|
||||
@@ -256,6 +254,25 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
|
||||
#define ADC_MULTIPLIER 3.2
|
||||
|
||||
#ifdef HELTEC_V2_0
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V2_0
|
||||
|
||||
#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HELTEC_V2_1
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V2_1
|
||||
|
||||
#define BATTERY_PIN 37 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(TLORA_V1)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TLORA_V1
|
||||
@@ -413,6 +430,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#define HW_VENDOR HardwareModel_RAK4631
|
||||
|
||||
#elif defined(TTGO_T_ECHO)
|
||||
|
||||
#define HW_VENDOR HardwareModel_T_ECHO
|
||||
|
||||
#elif NRF52_SERIES
|
||||
|
||||
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN
|
||||
@@ -423,11 +444,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#define USE_SIM_RADIO
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET RADIOLIB_NC
|
||||
#define LORA_DIO1 33 // Not really used
|
||||
#define LORA_DIO2 32 // Not really used
|
||||
// Pine64 uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||
// not found then probe for SX1262. Currently the RF95 code is disabled because I think the RF95 module won't need to ship.
|
||||
// #define USE_RF95
|
||||
#define USE_SX1262
|
||||
|
||||
// Fake SPI device selections
|
||||
#define RF95_SCK 5
|
||||
@@ -435,6 +455,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
|
||||
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 33 // SX1262 IRQ, called DIO0 on pinelora schematic, pin 7 on ch341f "ack" - FIXME, enable hwints in linux
|
||||
#define LORA_DIO2 32 // SX1262 BUSY, actually connected to "DIO5" on pinelora schematic, pin 8 on ch341f "slct"
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX1262_CS 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
|
||||
#define SX1262_DIO1 LORA_DIO1
|
||||
#define SX1262_BUSY LORA_DIO2
|
||||
#define SX1262_RESET LORA_RESET
|
||||
// HOPE RFM90 does not have a TCXO therefore not SX1262_E22
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// DEBUG LED
|
||||
|
||||
@@ -4,5 +4,8 @@
|
||||
|
||||
#include "mesh/generated/mesh.pb.h" // For CriticalErrorCode
|
||||
|
||||
/// A macro that include filename and line
|
||||
#define RECORD_CRITICALERROR(code) recordCriticalError(code, __LINE__, __FILE__)
|
||||
|
||||
/// Record an error that should be reported via analytics
|
||||
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_Unspecified, uint32_t address = 0);
|
||||
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_Unspecified, uint32_t address = 0, const char *filename = NULL);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "Air530GPS.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include "GPS.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "NMEAGPS.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
|
||||
static int32_t toDegInt(RawDegrees d)
|
||||
{
|
||||
|
||||
@@ -48,14 +48,22 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
shouldSet = false;
|
||||
|
||||
if (shouldSet) {
|
||||
lastSetMsec = now;
|
||||
#ifndef NO_ESP32
|
||||
settimeofday(tv, NULL);
|
||||
readFromRTC();
|
||||
#else
|
||||
lastSetMsec = now;
|
||||
|
||||
// This delta value works on all platforms
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv->tv_sec;
|
||||
|
||||
// If this platform has a setable RTC, set it
|
||||
#ifndef NO_ESP32
|
||||
settimeofday(tv, NULL);
|
||||
#endif
|
||||
|
||||
// nrf52 doesn't have a readable RTC (yet - software not written)
|
||||
#if defined(PORTDUINO) || !defined(NO_ESP32)
|
||||
readFromRTC();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -84,7 +92,7 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
|
||||
uint32_t getTime()
|
||||
{
|
||||
return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
||||
return (((uint32_t) millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
||||
}
|
||||
|
||||
uint32_t getValidTime(RTCQuality minQuality)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "UBloxGPS.h"
|
||||
#include "RTC.h"
|
||||
#include "error.h"
|
||||
@@ -43,7 +44,7 @@ bool UBloxGPS::setupGPS()
|
||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||
|
||||
if (!setUBXMode())
|
||||
recordCriticalError(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef HAS_EINK
|
||||
#include "EInkDisplay.h"
|
||||
#include "SPILock.h"
|
||||
#include "epd1in54.h" // Screen specific library
|
||||
#include <SPI.h>
|
||||
#include <TFT_eSPI.h> // Graphics library and Sprite class
|
||||
|
||||
Epd ePaper; // Create an instance ePaper
|
||||
|
||||
TFT_eSPI glc = TFT_eSPI(); // Invoke the graphics library class
|
||||
TFT_eSprite frame = TFT_eSprite(&glc); // Invoke the Sprite class for the image frame buffer
|
||||
uint8_t *framePtr; // Pointer for the black frame buffer
|
||||
|
||||
#define COLORED 0
|
||||
#define UNCOLORED 1
|
||||
|
||||
#define INK COLORED // Black ink
|
||||
#define PAPER UNCOLORED // 'paper' background colour
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Update display - different displays have different function names in the default
|
||||
// Waveshare libraries :-(
|
||||
//------------------------------------------------------------------------------------
|
||||
#if defined(EPD1IN54B_H) || defined(EPD1IN54C_H) || defined(EPD2IN13B_H) || defined(EPD2IN7B_H) || defined(EPD2IN9B_H) || \
|
||||
defined(EPD4IN2_H)
|
||||
void updateDisplay(uint8_t *blackFrame = blackFramePtr, uint8_t *redFrame = redFramePtr)
|
||||
{
|
||||
ePaper.DisplayFrame(blackFrame, redFrame); // Update 3 colour display
|
||||
#else
|
||||
void updateDisplay(uint8_t *blackFrame = framePtr)
|
||||
{
|
||||
#if defined(EPD2IN7_H) || defined(EPD4IN2_H)
|
||||
ePaper.DisplayFrame(blackFrame); // Update 2 color display
|
||||
|
||||
#elif defined(EPD1IN54_H) || defined(EPD2IN13_H) || defined(EPD2IN9_H)
|
||||
ePaper.SetFrameMemory(blackFrame); // Update 2 colour display
|
||||
ePaper.DisplayFrame();
|
||||
#else
|
||||
#error "Selected ePaper library is not supported"
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
|
||||
{
|
||||
setGeometry(GEOMETRY_RAWMODE, EPD_WIDTH, EPD_HEIGHT);
|
||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
||||
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
||||
}
|
||||
|
||||
// FIXME quick hack to limit drawing to a very slow rate
|
||||
uint32_t lastDrawMsec;
|
||||
|
||||
/**
|
||||
* Force a display update if we haven't drawn within the specified msecLimit
|
||||
*/
|
||||
bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
{
|
||||
// No need to grab this lock because we are on our own SPI bus
|
||||
// concurrency::LockGuard g(spiLock);
|
||||
|
||||
uint32_t now = millis();
|
||||
uint32_t sinceLast = now - lastDrawMsec;
|
||||
|
||||
if (framePtr && (sinceLast > msecLimit || lastDrawMsec == 0)) {
|
||||
lastDrawMsec = now;
|
||||
|
||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
|
||||
for (uint8_t y = 0; y < displayHeight; y++) {
|
||||
for (uint8_t x = 0; x < displayWidth; x++) {
|
||||
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto b = buffer[x + (y / 8) * displayWidth];
|
||||
auto isset = b & (1 << (y & 7));
|
||||
frame.drawPixel(x, y, isset ? INK : PAPER);
|
||||
}
|
||||
}
|
||||
|
||||
ePaper.Reset(); // wake the screen from sleep
|
||||
|
||||
DEBUG_MSG("Updating eink... ");
|
||||
updateDisplay(); // Send image to display and refresh
|
||||
DEBUG_MSG("done\n");
|
||||
|
||||
// Put screen to sleep to save power
|
||||
ePaper.Sleep();
|
||||
return true;
|
||||
} else {
|
||||
// DEBUG_MSG("Skipping eink display\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the buffer to the display memory
|
||||
void EInkDisplay::display(void)
|
||||
{
|
||||
// We don't allow regular 'dumb' display() calls to draw on eink until we've shown
|
||||
// at least one forceDisplay() keyframe. This prevents flashing when we should the critical
|
||||
// bootscreen (that we want to look nice)
|
||||
if (lastDrawMsec)
|
||||
forceDisplay(slowUpdateMsec); // Show the first screen a few seconds after boot, then slower
|
||||
}
|
||||
|
||||
// Send a command to the display (low level function)
|
||||
void EInkDisplay::sendCommand(uint8_t com)
|
||||
{
|
||||
(void)com;
|
||||
// Drop all commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
// Connect to the display
|
||||
bool EInkDisplay::connect()
|
||||
{
|
||||
DEBUG_MSG("Doing EInk init\n");
|
||||
|
||||
#ifdef PIN_EINK_PWR_ON
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
pinMode(PIN_EINK_PWR_ON, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_EINK_EN
|
||||
// backlight power, HIGH is backlight on, LOW is off
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
// Initialise the ePaper library
|
||||
// FIXME - figure out how to use lut_partial_update
|
||||
if (ePaper.Init(lut_full_update) != 0) {
|
||||
DEBUG_MSG("ePaper init failed\n");
|
||||
return false;
|
||||
} else {
|
||||
frame.setColorDepth(1); // Must set the bits per pixel to 1 for ePaper displays
|
||||
// Set bit depth BEFORE creating Sprite, default is 16!
|
||||
|
||||
// Create a frame buffer in RAM of defined size and save the pointer to it
|
||||
// RAM needed is about (EPD_WIDTH * EPD_HEIGHT)/8 , ~5000 bytes for 200 x 200 pixels
|
||||
// Note: always create the Sprite before setting the Sprite rotation
|
||||
framePtr = (uint8_t *)frame.createSprite(EPD_WIDTH, EPD_HEIGHT);
|
||||
|
||||
frame.fillSprite(PAPER); // Fill frame with white
|
||||
/* frame.drawLine(0, 0, frame.width() - 1, frame.height() - 1, INK);
|
||||
frame.drawLine(0, frame.height() - 1, frame.width() - 1, 0, INK);
|
||||
updateDisplay(); */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
116
src/graphics/EInkDisplay2.cpp
Normal file
116
src/graphics/EInkDisplay2.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef HAS_EINK
|
||||
#include "EInkDisplay2.h"
|
||||
#include "SPILock.h"
|
||||
#include <SPI.h>
|
||||
#include "GxEPD2_BW.h"
|
||||
|
||||
#define COLORED GxEPD_BLACK
|
||||
#define UNCOLORED GxEPD_WHITE
|
||||
|
||||
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67
|
||||
|
||||
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
||||
|
||||
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
|
||||
{
|
||||
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
|
||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
||||
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
||||
}
|
||||
|
||||
// FIXME quick hack to limit drawing to a very slow rate
|
||||
uint32_t lastDrawMsec;
|
||||
|
||||
/**
|
||||
* Force a display update if we haven't drawn within the specified msecLimit
|
||||
*/
|
||||
bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
{
|
||||
// No need to grab this lock because we are on our own SPI bus
|
||||
// concurrency::LockGuard g(spiLock);
|
||||
|
||||
uint32_t now = millis();
|
||||
uint32_t sinceLast = now - lastDrawMsec;
|
||||
|
||||
if (adafruitDisplay && (sinceLast > msecLimit || lastDrawMsec == 0)) {
|
||||
lastDrawMsec = now;
|
||||
|
||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
|
||||
for (uint8_t y = 0; y < displayHeight; y++) {
|
||||
for (uint8_t x = 0; x < displayWidth; x++) {
|
||||
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto b = buffer[x + (y / 8) * displayWidth];
|
||||
auto isset = b & (1 << (y & 7));
|
||||
adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG("Updating eink... ");
|
||||
// ePaper.Reset(); // wake the screen from sleep
|
||||
adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
||||
adafruitDisplay->hibernate();
|
||||
DEBUG_MSG("done\n");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// DEBUG_MSG("Skipping eink display\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the buffer to the display memory
|
||||
void EInkDisplay::display(void)
|
||||
{
|
||||
// We don't allow regular 'dumb' display() calls to draw on eink until we've shown
|
||||
// at least one forceDisplay() keyframe. This prevents flashing when we should the critical
|
||||
// bootscreen (that we want to look nice)
|
||||
if (lastDrawMsec)
|
||||
forceDisplay(slowUpdateMsec); // Show the first screen a few seconds after boot, then slower
|
||||
}
|
||||
|
||||
// Send a command to the display (low level function)
|
||||
void EInkDisplay::sendCommand(uint8_t com)
|
||||
{
|
||||
(void)com;
|
||||
// Drop all commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
// Connect to the display
|
||||
bool EInkDisplay::connect()
|
||||
{
|
||||
DEBUG_MSG("Doing EInk init\n");
|
||||
|
||||
#ifdef PIN_EINK_PWR_ON
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
pinMode(PIN_EINK_PWR_ON, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_EINK_EN
|
||||
// backlight power, HIGH is backlight on, LOW is off
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS,
|
||||
PIN_EINK_DC,
|
||||
PIN_EINK_RES,
|
||||
PIN_EINK_BUSY, SPI1);
|
||||
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
//adafruitDisplay->setFullWindow();
|
||||
//adafruitDisplay->fillScreen(UNCOLORED);
|
||||
//adafruitDisplay->drawCircle(100, 100, 20, COLORED);
|
||||
//adafruitDisplay->display(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,14 +19,13 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "configuration.h"
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "Screen.h"
|
||||
#include "configuration.h"
|
||||
#include "fonts.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/images.h"
|
||||
@@ -130,7 +129,7 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
|
||||
// Draw version in upper right
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%s",
|
||||
xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long
|
||||
xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
|
||||
screen->forceDisplay();
|
||||
|
||||
@@ -947,7 +946,9 @@ void Screen::setFrames()
|
||||
normalFrames[numframes++] = drawTextMessageFrame;
|
||||
|
||||
// then all the nodes
|
||||
for (size_t i = 0; i < numnodes; i++)
|
||||
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
|
||||
size_t numToShow = min(numnodes, 4U);
|
||||
for (size_t i = 0; i < numToShow; i++)
|
||||
normalFrames[numframes++] = drawNodeInfo;
|
||||
|
||||
// then the debug info
|
||||
|
||||
@@ -22,6 +22,8 @@ class Screen
|
||||
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
#include "../configuration.h"
|
||||
|
||||
#ifdef USE_SH1106
|
||||
#include <SH1106Wire.h>
|
||||
#elif defined(USE_ST7567)
|
||||
@@ -30,7 +32,7 @@ class Screen
|
||||
#include <SSD1306Wire.h>
|
||||
#endif
|
||||
|
||||
#include "EInkDisplay.h"
|
||||
#include "EInkDisplay2.h"
|
||||
#include "TFTDisplay.h"
|
||||
#include "TypedQueue.h"
|
||||
#include "commands.h"
|
||||
|
||||
38
src/main.cpp
38
src/main.cpp
@@ -1,4 +1,4 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "PowerFSM.h"
|
||||
#include "airtime.h"
|
||||
#include "buzz.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "power.h"
|
||||
// #include "rom/rtc.h"
|
||||
@@ -26,9 +25,10 @@
|
||||
#include <Wire.h>
|
||||
// #include <driver/rtc_io.h>
|
||||
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "mesh/http/WebServer.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#endif
|
||||
|
||||
@@ -299,6 +299,13 @@ uint32_t ButtonThread::longPressTime = 0;
|
||||
|
||||
RadioInterface *rIf = NULL;
|
||||
|
||||
/**
|
||||
* Some platforms (nrf52) might provide an alterate version that supresses calling delay from sleep.
|
||||
*/
|
||||
__attribute__ ((weak, noinline)) bool loopCanSleep() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
concurrency::hasBeenSetup = true;
|
||||
@@ -331,9 +338,10 @@ void setup()
|
||||
digitalWrite(RESET_OLED, 1);
|
||||
#endif
|
||||
|
||||
bool forceSoftAP = 0;
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
#ifndef NO_ESP32
|
||||
bool forceSoftAP = 0;
|
||||
|
||||
// If the button is connected to GPIO 12, don't enable the ability to use
|
||||
// meshtasticAdmin on the device.
|
||||
@@ -459,7 +467,7 @@ void setup()
|
||||
// Do this after service.init (because that clears error_code)
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
if (!axp192_found)
|
||||
recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
|
||||
#endif
|
||||
|
||||
// Don't call screen setup until after nodedb is setup (because we need
|
||||
@@ -499,7 +507,7 @@ void setup()
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("Radio init succeeded, using RF95 radio\n");
|
||||
DEBUG_MSG("RF95 Radio init succeeded, using RF95 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -512,7 +520,7 @@ void setup()
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("Radio init succeeded, using SX1262 radio\n");
|
||||
DEBUG_MSG("SX1262 Radio init succeeded, using SX1262 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -530,10 +538,14 @@ void setup()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#if defined(PORTDUINO) || defined(HAS_WIFI)
|
||||
mqttInit();
|
||||
#endif
|
||||
|
||||
// Initialize Wifi
|
||||
initWifi(forceSoftAP);
|
||||
|
||||
#ifndef NO_ESP32
|
||||
// Start web server thread.
|
||||
webServerThread = new WebServerThread();
|
||||
#endif
|
||||
@@ -542,15 +554,11 @@ void setup()
|
||||
initApiServer();
|
||||
#endif
|
||||
|
||||
#if defined(PORTDUINO) || defined(HAS_WIFI)
|
||||
mqttInit();
|
||||
#endif
|
||||
|
||||
// Start airtime logger thread.
|
||||
airTime = new AirTime();
|
||||
|
||||
if (!rIf)
|
||||
recordCriticalError(CriticalErrorCode_NoRadio);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_NoRadio);
|
||||
else
|
||||
router->addInterface(rIf);
|
||||
|
||||
@@ -640,7 +648,9 @@ void loop()
|
||||
mainController.nextThread->tillRun(millis())); */
|
||||
|
||||
// We want to sleep as long as possible here - because it saves power
|
||||
if (!runASAP)
|
||||
if (!runASAP && loopCanSleep()) {
|
||||
// if(delayMsec > 100) DEBUG_MSG("sleeping %ld\n", delayMsec);
|
||||
mainDelay.delay(delayMsec);
|
||||
}
|
||||
// if (didWake) DEBUG_MSG("wake!\n");
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "NodeDB.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "CryptoEngine.h"
|
||||
#include "configuration.h"
|
||||
#include "CryptoEngine.h"
|
||||
|
||||
void CryptoEngine::setKey(const CryptoKey &k)
|
||||
{
|
||||
@@ -32,6 +32,10 @@ void CryptoEngine::decrypt(uint32_t fromNode, uint64_t packetNum, size_t numByte
|
||||
void CryptoEngine::initNonce(uint32_t fromNode, uint64_t packetNum)
|
||||
{
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
*((uint64_t *)&nonce[0]) = packetNum;
|
||||
*((uint32_t *)&nonce[8]) = fromNode;
|
||||
|
||||
// use memcpy to avoid breaking strict-aliasing
|
||||
memcpy(nonce, &packetNum, sizeof(uint64_t));
|
||||
memcpy(nonce + sizeof(uint64_t), &fromNode, sizeof(uint32_t));
|
||||
//*((uint64_t *)&nonce[0]) = packetNum;
|
||||
//*((uint32_t *)&nonce[8]) = fromNode;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "DSRRouter.h"
|
||||
#include "configuration.h"
|
||||
#include "DSRRouter.h"
|
||||
|
||||
/* when we receive any packet
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "FloodingRouter.h"
|
||||
#include "configuration.h"
|
||||
#include "FloodingRouter.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
FloodingRouter::FloodingRouter() {}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "configuration.h"
|
||||
#include "MeshPacketQueue.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/// @return the priority of the specified packet
|
||||
inline uint32_t getPriority(MeshPacket *p)
|
||||
inline uint32_t getPriority(const MeshPacket *p)
|
||||
{
|
||||
auto pri = p->priority;
|
||||
return pri;
|
||||
}
|
||||
|
||||
/// @return "true" if "p1" is ordered before "p2"
|
||||
bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2)
|
||||
bool CompareMeshPacketFunc(const MeshPacket *p1, const MeshPacket *p2)
|
||||
{
|
||||
assert(p1 && p2);
|
||||
auto p1p = getPriority(p1), p2p = getPriority(p2);
|
||||
@@ -24,7 +25,12 @@ bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2)
|
||||
|
||||
MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {}
|
||||
|
||||
/** Some clients might not properly set priority, therefore we fix it here.
|
||||
bool MeshPacketQueue::empty() {
|
||||
return queue.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Some clients might not properly set priority, therefore we fix it here.
|
||||
*/
|
||||
void fixPriority(MeshPacket *p)
|
||||
{
|
||||
@@ -33,7 +39,7 @@ void fixPriority(MeshPacket *p)
|
||||
if (p->priority == MeshPacket_Priority_UNSET) {
|
||||
// if acks give high priority
|
||||
// if a reliable message give a bit higher default priority
|
||||
p->priority = (p->decoded.portnum == PortNum_ROUTING_APP) ? MeshPacket_Priority_ACK :
|
||||
p->priority = (p->decoded.portnum == PortNum_ROUTING_APP) ? MeshPacket_Priority_ACK :
|
||||
(p->want_ack ? MeshPacket_Priority_RELIABLE : MeshPacket_Priority_DEFAULT);
|
||||
}
|
||||
}
|
||||
@@ -41,51 +47,70 @@ void fixPriority(MeshPacket *p)
|
||||
/** enqueue a packet, return false if full */
|
||||
bool MeshPacketQueue::enqueue(MeshPacket *p)
|
||||
{
|
||||
|
||||
fixPriority(p);
|
||||
|
||||
// fixme if there is something lower priority in the queue that can be deleted to make space, delete that instead
|
||||
if (size() >= maxLen)
|
||||
return false;
|
||||
else {
|
||||
push(p);
|
||||
return true;
|
||||
// no space - try to replace a lower priority packet in the queue
|
||||
if (queue.size() >= maxLen) {
|
||||
return replaceLowerPriorityPacket(p);
|
||||
}
|
||||
|
||||
queue.push_back(p);
|
||||
std::push_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
|
||||
return true;
|
||||
}
|
||||
|
||||
MeshPacket *MeshPacketQueue::dequeue()
|
||||
{
|
||||
if (empty())
|
||||
if (empty()) {
|
||||
return NULL;
|
||||
else {
|
||||
auto p = top();
|
||||
pop(); // remove the first item
|
||||
return p;
|
||||
}
|
||||
|
||||
auto *p = queue.front();
|
||||
std::pop_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
|
||||
queue.pop_back();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// this is kinda yucky, but I'm not sure if all arduino c++ compilers support closuers. And we only have one
|
||||
// thread that can run at a time - so safe
|
||||
static NodeNum findFrom;
|
||||
static PacketId findId;
|
||||
|
||||
static bool isMyPacket(MeshPacket *p)
|
||||
{
|
||||
return p->id == findId && getFrom(p) == findFrom;
|
||||
}
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
|
||||
/** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */
|
||||
MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
|
||||
{
|
||||
findFrom = from;
|
||||
findId = id;
|
||||
auto it = std::find_if(this->c.begin(), this->c.end(), isMyPacket);
|
||||
if (it != this->c.end()) {
|
||||
auto p = *it;
|
||||
this->c.erase(it);
|
||||
std::make_heap(this->c.begin(), this->c.end(), this->comp);
|
||||
return p;
|
||||
} else {
|
||||
return NULL;
|
||||
for (auto it = queue.begin(); it != queue.end(); it++) {
|
||||
auto p = (*it);
|
||||
if (getFrom(p) == from && p->id == id) {
|
||||
queue.erase(it);
|
||||
std::make_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
|
||||
bool MeshPacketQueue::replaceLowerPriorityPacket(MeshPacket *p) {
|
||||
std::sort_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc); // sort ascending based on priority (0 -> 127)
|
||||
|
||||
// find first packet which does not compare less (in priority) than parameter packet
|
||||
auto low = std::lower_bound(queue.begin(), queue.end(), p, &CompareMeshPacketFunc);
|
||||
|
||||
if (low == queue.begin()) { // if already at start, there are no packets with lower priority
|
||||
return false;
|
||||
}
|
||||
|
||||
if (low == queue.end()) {
|
||||
// all priorities in the vector are smaller than the incoming packet. Replace the lowest priority (first) element
|
||||
low = queue.begin();
|
||||
} else {
|
||||
// 'low' iterator points to first packet which does not compare less than parameter
|
||||
--low; // iterate to lower priority packet
|
||||
}
|
||||
|
||||
if (getPriority(p) > getPriority(*low)) {
|
||||
packetPool.release(*low); // deallocate and drop the packet we're replacing
|
||||
*low = p; // replace low-pri packet at this position with incoming packet with higher priority
|
||||
}
|
||||
|
||||
std::make_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,29 +5,29 @@
|
||||
#include <assert.h>
|
||||
#include <queue>
|
||||
|
||||
// this is an strucure which implements the
|
||||
// operator overloading
|
||||
struct CompareMeshPacket {
|
||||
bool operator()(MeshPacket *p1, MeshPacket *p2);
|
||||
};
|
||||
|
||||
/**
|
||||
* A priority queue of packets.
|
||||
*
|
||||
* A priority queue of packets
|
||||
*/
|
||||
class MeshPacketQueue : public std::priority_queue<MeshPacket *, std::vector<MeshPacket *>, CompareMeshPacket>
|
||||
class MeshPacketQueue
|
||||
{
|
||||
size_t maxLen;
|
||||
std::vector<MeshPacket *> queue;
|
||||
|
||||
/** Replace a lower priority package in the queue with 'mp' (provided there are lower pri packages). Return true if replaced. */
|
||||
bool replaceLowerPriorityPacket(MeshPacket *mp);
|
||||
|
||||
public:
|
||||
MeshPacketQueue(size_t _maxLen);
|
||||
|
||||
/** enqueue a packet, return false if full */
|
||||
bool enqueue(MeshPacket *p);
|
||||
|
||||
// bool isEmpty();
|
||||
/** return true if the queue is empty */
|
||||
bool empty();
|
||||
|
||||
MeshPacket *dequeue();
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
|
||||
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
|
||||
MeshPacket *remove(NodeNum from, PacketId id);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "MeshPlugin.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshService.h"
|
||||
@@ -86,10 +87,11 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||
|
||||
DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
|
||||
|
||||
if (wantsPacket) {
|
||||
DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
|
||||
pluginFound = true;
|
||||
|
||||
/// received channel (or NULL if not decoded)
|
||||
@@ -97,17 +99,21 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
|
||||
/// Is the channel this packet arrived on acceptable? (security check)
|
||||
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel plugins
|
||||
bool rxChannelOk = !pi.boundChannel || (ch && ((mp.from == 0) || (strcmp(ch->settings.name, pi.boundChannel) == 0)));
|
||||
|
||||
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and it needs to
|
||||
/// to be able to fetch the initial admin packets without yet knowing any channels.
|
||||
|
||||
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (ch && (strcmp(ch->settings.name, pi.boundChannel) == 0));
|
||||
|
||||
if (!rxChannelOk) {
|
||||
// no one should have already replied!
|
||||
assert(!currentReply);
|
||||
|
||||
if (mp.decoded.want_response) {
|
||||
DEBUG_MSG("packet on wrong channel, returning error\n");
|
||||
printPacket("packet on wrong channel, returning error", &mp);
|
||||
currentReply = pi.allocErrorResponse(Routing_Error_NOT_AUTHORIZED, &mp);
|
||||
} else
|
||||
DEBUG_MSG("packet on wrong channel, but client didn't want response\n");
|
||||
printPacket("packet on wrong channel, but can't respond", &mp);
|
||||
} else {
|
||||
|
||||
bool handled = pi.handleReceived(mp);
|
||||
@@ -149,7 +155,9 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
printPacket("Sending response", currentReply);
|
||||
service.sendToMesh(currentReply);
|
||||
currentReply = NULL;
|
||||
} else {
|
||||
} else if(mp.from != ourNodeNum) {
|
||||
// Note: if the message started with the local node we don't want to send a no response reply
|
||||
|
||||
// No one wanted to reply to this requst, tell the requster that happened
|
||||
DEBUG_MSG("No one responded, send a nak\n");
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
|
||||
@@ -67,7 +66,7 @@ void MeshService::init()
|
||||
|
||||
int MeshService::handleFromRadio(const MeshPacket *mp)
|
||||
{
|
||||
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
|
||||
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
|
||||
|
||||
printPacket("Forwarding to phone", mp);
|
||||
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include "FS.h"
|
||||
@@ -14,7 +13,6 @@
|
||||
#include "PowerFSM.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
@@ -541,15 +539,24 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
|
||||
}
|
||||
|
||||
/// Record an error that should be reported via analytics
|
||||
void recordCriticalError(CriticalErrorCode code, uint32_t address)
|
||||
void recordCriticalError(CriticalErrorCode code, uint32_t address, const char *filename)
|
||||
{
|
||||
// Print error to screen and serial port
|
||||
String lcd = String("Critical error ") + code + "!\n";
|
||||
screen->print(lcd.c_str());
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
|
||||
if(filename)
|
||||
DEBUG_MSG("NOTE! Recording critical error %d at %s:%lx\n", code, filename, address);
|
||||
else
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
|
||||
|
||||
// Record error to DB
|
||||
myNodeInfo.error_code = code;
|
||||
myNodeInfo.error_address = address;
|
||||
myNodeInfo.error_count++;
|
||||
|
||||
// Currently portuino is mostly used for simulation. Make sue the user notices something really bad happend
|
||||
#ifdef PORTDUINO
|
||||
DEBUG_MSG("A critical failure occurred, portduino is exiting...");
|
||||
exit(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "PacketHistory.h"
|
||||
#include "configuration.h"
|
||||
#include "PacketHistory.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
PacketHistory::PacketHistory()
|
||||
@@ -19,35 +19,57 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
||||
}
|
||||
|
||||
uint32_t now = millis();
|
||||
for (size_t i = 0; i < recentPackets.size();) {
|
||||
PacketRecord &r = recentPackets[i];
|
||||
|
||||
if ((now - r.rxTimeMsec) >= FLOOD_EXPIRE_TIME) {
|
||||
// DEBUG_MSG("Deleting old broadcast record %d\n", i);
|
||||
recentPackets.erase(recentPackets.begin() + i); // delete old record
|
||||
PacketRecord r;
|
||||
r.id = p->id;
|
||||
r.sender = getFrom(p);
|
||||
r.rxTimeMsec = now;
|
||||
|
||||
auto found = recentPackets.find(r);
|
||||
bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently
|
||||
|
||||
if (seenRecently && (now - found->rxTimeMsec) >= FLOOD_EXPIRE_TIME) { // Check whether found packet has already expired
|
||||
recentPackets.erase(found); // Erase and pretend packet has not been seen recently
|
||||
found = recentPackets.end();
|
||||
seenRecently = false;
|
||||
}
|
||||
|
||||
if (seenRecently) {
|
||||
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x\n", p->from, p->to, p->id);
|
||||
}
|
||||
|
||||
if (withUpdate) {
|
||||
if (found != recentPackets.end()) { // delete existing to updated timestamp (re-insert)
|
||||
recentPackets.erase(found); // as unsorted_set::iterator is const (can't update timestamp - so re-insert..)
|
||||
}
|
||||
recentPackets.insert(r);
|
||||
printPacket("Add packet record", p);
|
||||
}
|
||||
|
||||
// Capacity is reerved, so only purge expired packets if recentPackets fills past 90% capacity
|
||||
// Expiry is normally dealt with after having searched/found a packet (above)
|
||||
if (recentPackets.size() > (MAX_NUM_NODES * 0.9)) {
|
||||
clearExpiredRecentPackets();
|
||||
}
|
||||
|
||||
return seenRecently;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all recent packets, and remove all older than FLOOD_EXPIRE_TIME
|
||||
*/
|
||||
void PacketHistory::clearExpiredRecentPackets() {
|
||||
uint32_t now = millis();
|
||||
|
||||
DEBUG_MSG("recentPackets size=%ld\n", recentPackets.size());
|
||||
|
||||
for (auto it = recentPackets.begin(); it != recentPackets.end(); ) {
|
||||
if ((now - it->rxTimeMsec) >= FLOOD_EXPIRE_TIME) {
|
||||
it = recentPackets.erase(it); // erase returns iterator pointing to element immediately following the one erased
|
||||
} else {
|
||||
if (r.id == p->id && r.sender == getFrom(p)) {
|
||||
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
|
||||
// Update the time on this record to now
|
||||
if (withUpdate)
|
||||
r.rxTimeMsec = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
i++;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find an existing record, make one
|
||||
if (withUpdate) {
|
||||
PacketRecord r;
|
||||
r.id = p->id;
|
||||
r.sender = getFrom(p);
|
||||
r.rxTimeMsec = now;
|
||||
recentPackets.push_back(r);
|
||||
printPacket("Adding packet record", p);
|
||||
}
|
||||
|
||||
return false;
|
||||
DEBUG_MSG("recentPackets size=%ld (after clearing expired packets)\n", recentPackets.size());
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Router.h"
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/// We clear our old flood record five minute after we see the last of it
|
||||
#define FLOOD_EXPIRE_TIME (5 * 60 * 1000L)
|
||||
|
||||
@@ -23,26 +20,7 @@ struct PacketRecord {
|
||||
class PacketRecordHashFunction
|
||||
{
|
||||
public:
|
||||
size_t operator()(const PacketRecord &p) const { return (hash<NodeNum>()(p.sender)) ^ (hash<PacketId>()(p.id)); }
|
||||
};
|
||||
|
||||
/// Order packet records by arrival time, we want the oldest packets to be in the front of our heap
|
||||
class PacketRecordOrderFunction
|
||||
{
|
||||
public:
|
||||
size_t operator()(const PacketRecord &p1, const PacketRecord &p2) const
|
||||
{
|
||||
// If the timer ticks have rolled over the difference between times will be _enormous_. Handle that case specially
|
||||
uint32_t t1 = p1.rxTimeMsec, t2 = p2.rxTimeMsec;
|
||||
|
||||
if (t1 - t2 > UINT32_MAX / 2) {
|
||||
// time must have rolled over, swap them because the new little number is 'bigger' than the old big number
|
||||
t1 = t2;
|
||||
t2 = p1.rxTimeMsec;
|
||||
}
|
||||
|
||||
return t1 > t2;
|
||||
}
|
||||
size_t operator()(const PacketRecord &p) const { return (std::hash<NodeNum>()(p.sender)) ^ (std::hash<PacketId>()(p.id)); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -51,12 +29,9 @@ class PacketRecordOrderFunction
|
||||
class PacketHistory
|
||||
{
|
||||
private:
|
||||
/** FIXME: really should be a std::unordered_set with the key being sender,id.
|
||||
* This would make checking packets in wasSeenRecently faster.
|
||||
*/
|
||||
vector<PacketRecord> recentPackets;
|
||||
// priority_queue<PacketRecord, vector<PacketRecord>, PacketRecordOrderFunction> arrivalTimes;
|
||||
// unordered_set<PacketRecord, PacketRecordHashFunction> recentPackets;
|
||||
std::unordered_set<PacketRecord, PacketRecordHashFunction> recentPackets;
|
||||
|
||||
void clearExpiredRecentPackets(); // clear all recentPackets older than FLOOD_EXPIRE_TIME
|
||||
|
||||
public:
|
||||
PacketHistory();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "PhoneAPI.h"
|
||||
#include "Channels.h"
|
||||
#include "GPS.h"
|
||||
@@ -27,6 +28,7 @@ PhoneAPI::~PhoneAPI()
|
||||
|
||||
void PhoneAPI::handleStartConfig()
|
||||
{
|
||||
// Must be before setting state (because state is how we know !connected)
|
||||
if (!isConnected()) {
|
||||
onConnectionChanged(true);
|
||||
observe(&service.fromNumChanged);
|
||||
@@ -35,7 +37,7 @@ void PhoneAPI::handleStartConfig()
|
||||
// even if we were already connected - restart our state machine
|
||||
state = STATE_SEND_MY_INFO;
|
||||
|
||||
DEBUG_MSG("Reset nodeinfo read pointer\n");
|
||||
DEBUG_MSG("Starting API client config\n");
|
||||
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
|
||||
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
|
||||
// this will break once we have multiple instances of PhoneAPI running independently
|
||||
@@ -56,10 +58,9 @@ void PhoneAPI::close()
|
||||
void PhoneAPI::checkConnectionTimeout()
|
||||
{
|
||||
if (isConnected()) {
|
||||
uint32_t now = millis();
|
||||
bool newContact = (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL;
|
||||
bool newContact = checkIsConnected();
|
||||
if (!newContact) {
|
||||
DEBUG_MSG("Timed out on phone contact, dropping phone connection\n");
|
||||
DEBUG_MSG("Lost phone connection\n");
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -93,7 +94,8 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
||||
// Ignore nop messages
|
||||
// DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -50,9 +50,6 @@ class PhoneAPI
|
||||
/// Use to ensure that clients don't get confused about old messages from the radio
|
||||
uint32_t config_nonce = 0;
|
||||
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
|
||||
public:
|
||||
PhoneAPI();
|
||||
|
||||
@@ -84,16 +81,25 @@ class PhoneAPI
|
||||
|
||||
bool isConnected() { return state != STATE_SEND_NOTHING; }
|
||||
|
||||
/// emit a debugging log character, FIXME - implement
|
||||
void debugOut(char c) { }
|
||||
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
FromRadio fromRadioScratch;
|
||||
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected) {}
|
||||
|
||||
/// If we haven't heard from the other side in a while then say not connected
|
||||
void checkConnectionTimeout();
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() = 0;
|
||||
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "ProtobufPlugin.h"
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
|
||||
* In general decoded will always be !NULL. But in some special applications (where you have handling packets
|
||||
* for multiple port numbers, decoding will ONLY be attempted for packets where the portnum matches our expected ourPortNum.
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T *decoded) = 0;
|
||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, T *decoded) = 0;
|
||||
|
||||
/**
|
||||
* Return a mesh packet which has been preinited with a particular protobuf data payload and port number.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "configuration.h"
|
||||
#include "RF95Interface.h"
|
||||
#include "MeshRadio.h" // kinda yucky, but we need to know which region we are in
|
||||
#include "RadioLibRF95.h"
|
||||
#include "error.h"
|
||||
#include <configuration.h>
|
||||
|
||||
#define MAX_POWER 20
|
||||
// if we use 20 we are limited to 1% duty cycle or hw might overheat. For continuous operation set a limit of 17
|
||||
@@ -94,15 +94,15 @@ bool RF95Interface::reconfigure()
|
||||
// configure publicly accessible settings
|
||||
int err = lora->setSpreadingFactor(sf);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setBandwidth(bw);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setCodingRate(cr);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setSyncWord(syncWord);
|
||||
assert(err == ERR_NONE);
|
||||
@@ -115,13 +115,13 @@ bool RF95Interface::reconfigure()
|
||||
|
||||
err = lora->setFrequency(freq);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > MAX_POWER) // This chip has lower power limits than some
|
||||
power = MAX_POWER;
|
||||
err = lora->setOutputPower(power);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
startReceive(); // restart receiving
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ class RF95Interface : public RadioLibInterface
|
||||
public:
|
||||
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
|
||||
|
||||
/// Some boards (Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||
bool isIRQPending() { return lora->getPendingIRQ(); }
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshRadio.h"
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "NodeDB.h"
|
||||
#include "Router.h"
|
||||
#include "assert.h"
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
@@ -151,6 +151,9 @@ class RadioInterface
|
||||
*/
|
||||
float getFreq();
|
||||
|
||||
/// Some boards (1st gen Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||
virtual bool isIRQPending() { return false; }
|
||||
|
||||
protected:
|
||||
int8_t power = 17; // Set by applyModemConfig()
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "configuration.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "NodeDB.h"
|
||||
#include "SPILock.h"
|
||||
#include "error.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <configuration.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
|
||||
@@ -75,7 +75,7 @@ bool RadioLibInterface::canSendImmediately()
|
||||
// TX IRQ from the radio, the radio is probably broken.
|
||||
if (busyTx && (millis() - lastTxStart > 60000)) {
|
||||
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
|
||||
recordCriticalError(CriticalErrorCode_TransmitFailed);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_TransmitFailed);
|
||||
#ifndef NO_ESP32
|
||||
if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot
|
||||
ESP.restart();
|
||||
@@ -312,7 +312,13 @@ void RadioLibInterface::startSend(MeshPacket *txp)
|
||||
size_t numbytes = beginSending(txp);
|
||||
|
||||
int res = iface->startTransmit(radiobuf, numbytes);
|
||||
assert(res == ERR_NONE);
|
||||
if(res != ERR_NONE) {
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug);
|
||||
|
||||
// This send failed, but make sure to 'complete' it properly
|
||||
completeSending();
|
||||
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
|
||||
}
|
||||
|
||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
|
||||
enableInterrupt(isrTxLevel0);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "configuration.h"
|
||||
#include "RadioLibRF95.h"
|
||||
|
||||
#define RF95_CHIP_VERSION 0x12
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "configuration.h"
|
||||
#include "ReliableRouter.h"
|
||||
#include "MeshPlugin.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
// ReliableRouter::ReliableRouter() {}
|
||||
@@ -49,6 +49,9 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
|
||||
stopRetransmission(key);
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("didn't find pending packet\n");
|
||||
}
|
||||
}
|
||||
|
||||
return FloodingRouter::shouldFilterReceived(p);
|
||||
|
||||
@@ -51,7 +51,7 @@ struct PendingPacket {
|
||||
class GlobalPacketIdHashFunction
|
||||
{
|
||||
public:
|
||||
size_t operator()(const GlobalPacketId &p) const { return (hash<NodeNum>()(p.node)) ^ (hash<PacketId>()(p.id)); }
|
||||
size_t operator()(const GlobalPacketId &p) const { return (std::hash<NodeNum>()(p.node)) ^ (std::hash<PacketId>()(p.id)); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ class GlobalPacketIdHashFunction
|
||||
class ReliableRouter : public FloodingRouter
|
||||
{
|
||||
private:
|
||||
unordered_map<GlobalPacketId, PendingPacket, GlobalPacketIdHashFunction> pending;
|
||||
std::unordered_map<GlobalPacketId, PendingPacket, GlobalPacketIdHashFunction> pending;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "configuration.h"
|
||||
#include "Router.h"
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "SX1262Interface.h"
|
||||
#include "error.h"
|
||||
#include <configuration.h>
|
||||
|
||||
// Particular boards might define a different max power based on what their hardware can do
|
||||
#ifndef SX1262_MAX_POWER
|
||||
@@ -59,6 +59,30 @@ bool SX1262Interface::init()
|
||||
res = lora.setDio2AsRfSwitch(false);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Read/write a register we are not using (only used for FSK mode) to test SPI comms
|
||||
uint8_t crcLSB = 0;
|
||||
int err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
//if(crcLSB != 0x0f)
|
||||
// RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
crcLSB = 0x5a;
|
||||
err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
if(crcLSB != 0x5a)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
// If we got this far register accesses (and therefore SPI comms) are good
|
||||
#endif
|
||||
|
||||
if (res == ERR_NONE)
|
||||
res = lora.setCRC(SX126X_LORA_CRC_ON);
|
||||
|
||||
@@ -78,15 +102,15 @@ bool SX1262Interface::reconfigure()
|
||||
// configure publicly accessible settings
|
||||
int err = lora.setSpreadingFactor(sf);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setBandwidth(bw);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setCodingRate(cr);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
|
||||
err = lora.setRxGain(true);
|
||||
@@ -103,7 +127,7 @@ bool SX1262Interface::reconfigure()
|
||||
|
||||
err = lora.setFrequency(freq);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
@@ -122,6 +146,8 @@ void INTERRUPT_ATTR SX1262Interface::disableInterrupt()
|
||||
|
||||
void SX1262Interface::setStandby()
|
||||
{
|
||||
checkNotification(); // handle any pending interrupts before we force standby
|
||||
|
||||
int err = lora.standby();
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ class SX1262Interface : public RadioLibInterface
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep();
|
||||
|
||||
bool isIRQPending() { return lora.getIrqStatus() != 0; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Glue functions called from ISR land
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "StreamAPI.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#define START1 0x94
|
||||
@@ -25,40 +26,49 @@ int32_t StreamAPI::readStream()
|
||||
return recentRx ? 5 : 250;
|
||||
} else {
|
||||
while (stream->available()) { // Currently we never want to block
|
||||
uint8_t c = stream->read();
|
||||
int cInt = stream->read();
|
||||
if(cInt < 0)
|
||||
break; // We ran out of characters (even though available said otherwise) - this can happen on rf52 adafruit arduino
|
||||
|
||||
uint8_t c = (uint8_t) cInt;
|
||||
|
||||
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
|
||||
size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
|
||||
size_t ptr = rxPtr;
|
||||
|
||||
rxPtr++; // assume we will probably advance the rxPtr
|
||||
rxBuf[ptr] = c; // store all bytes (including framing)
|
||||
|
||||
// console->printf("rxPtr %d ptr=%d c=0x%x\n", rxPtr, ptr, c);
|
||||
|
||||
if (ptr == 0) { // looking for START1
|
||||
if (c != START1)
|
||||
rxPtr = 0; // failed to find framing
|
||||
} else if (ptr == 1) { // looking for START2
|
||||
if (c != START2)
|
||||
rxPtr = 0; // failed to find framing
|
||||
} else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
|
||||
} else if (ptr >= HEADER_LEN - 1) { // we have at least read our 4 byte framing
|
||||
uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
|
||||
|
||||
if (ptr == HEADER_LEN) {
|
||||
// console->printf("len %d\n", len);
|
||||
|
||||
if (ptr == HEADER_LEN - 1) {
|
||||
// we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
|
||||
// protobuf also)
|
||||
if (len > MAX_TO_FROM_RADIO_SIZE)
|
||||
rxPtr = 0; // length is bogus, restart search for framing
|
||||
}
|
||||
|
||||
if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
|
||||
rxPtr = 0; // start over again on the next packet
|
||||
if (rxPtr != 0) // Is packet still considered 'good'?
|
||||
if (ptr + 1 >= len + HEADER_LEN) { // have we received all of the payload?
|
||||
rxPtr = 0; // start over again on the next packet
|
||||
|
||||
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
||||
if (handleToRadio(rxBuf + HEADER_LEN, len))
|
||||
return 0; // we want to be called again ASAP because we still have more work to do
|
||||
}
|
||||
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
||||
handleToRadio(rxBuf + HEADER_LEN, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we had packets available this time, so assume we might have them next time also
|
||||
// we had bytes available this time, so assume we might have them next time also
|
||||
lastRxMsec = now;
|
||||
return 0;
|
||||
}
|
||||
@@ -109,4 +119,18 @@ void StreamAPI::emitRebooted()
|
||||
|
||||
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void StreamAPI::onConnectionChanged(bool connected)
|
||||
{
|
||||
// FIXME do reference counting instead
|
||||
|
||||
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
// FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't
|
||||
// received a packet in a while
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,11 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
||||
*/
|
||||
void emitRebooted();
|
||||
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() = 0;
|
||||
|
||||
/**
|
||||
* Send the current txBuffer over our stream
|
||||
*/
|
||||
|
||||
@@ -17,11 +17,12 @@ typedef enum _HardwareModel {
|
||||
HardwareModel_TLORA_V1 = 2,
|
||||
HardwareModel_TLORA_V2_1_1p6 = 3,
|
||||
HardwareModel_TBEAM = 4,
|
||||
HardwareModel_HELTEC = 5,
|
||||
HardwareModel_HELTEC_V2_0 = 5,
|
||||
HardwareModel_TBEAM0p7 = 6,
|
||||
HardwareModel_T_ECHO = 7,
|
||||
HardwareModel_TLORA_V1_1p3 = 8,
|
||||
HardwareModel_RAK4631 = 9,
|
||||
HardwareModel_HELTEC_V2_1 = 10,
|
||||
HardwareModel_LORA_RELAY_V1 = 32,
|
||||
HardwareModel_NRF52840DK = 33,
|
||||
HardwareModel_PPR = 34,
|
||||
@@ -33,7 +34,7 @@ typedef enum _HardwareModel {
|
||||
|
||||
typedef enum _Constants {
|
||||
Constants_Unused = 0,
|
||||
Constants_DATA_PAYLOAD_LEN = 240
|
||||
Constants_DATA_PAYLOAD_LEN = 237
|
||||
} Constants;
|
||||
|
||||
typedef enum _CriticalErrorCode {
|
||||
@@ -46,7 +47,9 @@ typedef enum _CriticalErrorCode {
|
||||
CriticalErrorCode_NoAXP192 = 6,
|
||||
CriticalErrorCode_InvalidRadioSetting = 7,
|
||||
CriticalErrorCode_TransmitFailed = 8,
|
||||
CriticalErrorCode_Brownout = 9
|
||||
CriticalErrorCode_Brownout = 9,
|
||||
CriticalErrorCode_SX1262Failure = 10,
|
||||
CriticalErrorCode_RadioSpiBug = 11
|
||||
} CriticalErrorCode;
|
||||
|
||||
typedef enum _Routing_Error {
|
||||
@@ -216,8 +219,8 @@ typedef struct _ToRadio {
|
||||
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
|
||||
|
||||
#define _CriticalErrorCode_MIN CriticalErrorCode_None
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_Brownout
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_Brownout+1))
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_RadioSpiBug
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_RadioSpiBug+1))
|
||||
|
||||
#define _Routing_Error_MIN Routing_Error_NONE
|
||||
#define _Routing_Error_MAX Routing_Error_NOT_AUTHORIZED
|
||||
|
||||
@@ -40,7 +40,9 @@ class HttpAPI : public PhoneAPI
|
||||
// Nothing here yet
|
||||
|
||||
protected:
|
||||
// Nothing here yet
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() { return true; } // FIXME, be smarter about this
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <HTTPMultipartBodyParser.hpp>
|
||||
#include <HTTPURLEncodedBodyParser.hpp>
|
||||
|
||||
|
||||
#include <WebServer.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
@@ -13,7 +12,6 @@
|
||||
#include "esp_task_wdt.h"
|
||||
#endif
|
||||
|
||||
|
||||
// Persistant Data Storage
|
||||
#include <Preferences.h>
|
||||
Preferences prefs;
|
||||
@@ -42,46 +40,41 @@ Preferences prefs;
|
||||
using namespace httpsserver;
|
||||
#include "mesh/http/ContentHandler.h"
|
||||
|
||||
SSLCert *cert;
|
||||
HTTPSServer *secureServer;
|
||||
HTTPServer *insecureServer;
|
||||
static SSLCert *cert;
|
||||
static HTTPSServer *secureServer;
|
||||
static HTTPServer *insecureServer;
|
||||
|
||||
volatile bool isWebServerReady;
|
||||
volatile bool isCertReady;
|
||||
|
||||
|
||||
|
||||
bool isWebServerReady = 0;
|
||||
bool isCertReady = 0;
|
||||
|
||||
|
||||
void handleWebResponse()
|
||||
static void handleWebResponse()
|
||||
{
|
||||
if (isWifiAvailable() == 0) {
|
||||
return;
|
||||
}
|
||||
if (isWifiAvailable()) {
|
||||
|
||||
if (isWebServerReady) {
|
||||
// We're going to handle the DNS responder here so it
|
||||
// will be ignored by the NRF boards.
|
||||
handleDNSResponse();
|
||||
if (isWebServerReady) {
|
||||
// We're going to handle the DNS responder here so it
|
||||
// will be ignored by the NRF boards.
|
||||
handleDNSResponse();
|
||||
|
||||
secureServer->loop();
|
||||
insecureServer->loop();
|
||||
}
|
||||
if(secureServer)
|
||||
secureServer->loop();
|
||||
insecureServer->loop();
|
||||
}
|
||||
|
||||
/*
|
||||
Slow down the CPU if we have not received a request within the last few
|
||||
seconds.
|
||||
*/
|
||||
|
||||
if (millis() - getTimeSpeedUp() >= (25 * 1000)) {
|
||||
setCpuFrequencyMhz(80);
|
||||
setTimeSpeedUp();
|
||||
/*
|
||||
Slow down the CPU if we have not received a request within the last few
|
||||
seconds.
|
||||
*/
|
||||
|
||||
if (millis() - getTimeSpeedUp() >= (25 * 1000)) {
|
||||
setCpuFrequencyMhz(80);
|
||||
setTimeSpeedUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void taskCreateCert(void *parameter)
|
||||
static void taskCreateCert(void *parameter)
|
||||
{
|
||||
|
||||
prefs.begin("MeshtasticHTTPS", false);
|
||||
|
||||
// Delete the saved certs
|
||||
@@ -92,13 +85,32 @@ void taskCreateCert(void *parameter)
|
||||
prefs.remove("cert");
|
||||
}
|
||||
|
||||
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
|
||||
|
||||
size_t pkLen = prefs.getBytesLength("PK");
|
||||
size_t certLen = prefs.getBytesLength("cert");
|
||||
|
||||
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
|
||||
|
||||
if (pkLen && certLen) {
|
||||
DEBUG_MSG("Existing SSL Certificate found!\n");
|
||||
|
||||
uint8_t *pkBuffer = new uint8_t[pkLen];
|
||||
prefs.getBytes("PK", pkBuffer, pkLen);
|
||||
|
||||
uint8_t *certBuffer = new uint8_t[certLen];
|
||||
prefs.getBytes("cert", certBuffer, certLen);
|
||||
|
||||
cert = new SSLCert(certBuffer, certLen, pkBuffer, pkLen);
|
||||
|
||||
DEBUG_MSG("Retrieved Private Key: %d Bytes\n", cert->getPKLength());
|
||||
// DEBUG_MSG("Retrieved Private Key: " + String(cert->getPKLength()) + " Bytes");
|
||||
// for (int i = 0; i < cert->getPKLength(); i++)
|
||||
// Serial.print(cert->getPKData()[i], HEX);
|
||||
// Serial.println();
|
||||
|
||||
DEBUG_MSG("Retrieved Certificate: %d Bytes\n", cert->getCertLength());
|
||||
// for (int i = 0; i < cert->getCertLength(); i++)
|
||||
// Serial.print(cert->getCertData()[i], HEX);
|
||||
// Serial.println();
|
||||
} else {
|
||||
DEBUG_MSG("Creating the certificate. This may take a while. Please wait...\n");
|
||||
yield();
|
||||
@@ -133,35 +145,35 @@ void taskCreateCert(void *parameter)
|
||||
}
|
||||
}
|
||||
|
||||
isCertReady = 1;
|
||||
isCertReady = true;
|
||||
|
||||
// Must delete self, can't just fall out
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void createSSLCert()
|
||||
{
|
||||
if (isWifiAvailable() && !isCertReady) {
|
||||
|
||||
if (isWifiAvailable() == 0) {
|
||||
return;
|
||||
// Create a new process just to handle creating the cert.
|
||||
// This is a workaround for Bug: https://github.com/fhessel/esp32_https_server/issues/48
|
||||
// jm@casler.org (Oct 2020)
|
||||
xTaskCreate(taskCreateCert, /* Task function. */
|
||||
"createCert", /* String with name of task. */
|
||||
16384, /* Stack size in bytes. */
|
||||
NULL, /* Parameter passed as input of the task */
|
||||
16, /* Priority of the task. */
|
||||
NULL); /* Task handle. */
|
||||
|
||||
DEBUG_MSG("Waiting for SSL Cert to be generated.\n");
|
||||
while (!isCertReady) {
|
||||
DEBUG_MSG(".");
|
||||
delay(1000);
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
DEBUG_MSG("SSL Cert Ready!\n");
|
||||
}
|
||||
|
||||
// Create a new process just to handle creating the cert.
|
||||
// This is a workaround for Bug: https://github.com/fhessel/esp32_https_server/issues/48
|
||||
// jm@casler.org (Oct 2020)
|
||||
xTaskCreate(taskCreateCert, /* Task function. */
|
||||
"createCert", /* String with name of task. */
|
||||
16384, /* Stack size in bytes. */
|
||||
NULL, /* Parameter passed as input of the task */
|
||||
16, /* Priority of the task. */
|
||||
NULL); /* Task handle. */
|
||||
|
||||
DEBUG_MSG("Waiting for SSL Cert to be generated.\n");
|
||||
while (!isCertReady) {
|
||||
DEBUG_MSG(".");
|
||||
delay(1000);
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
DEBUG_MSG("SSL Cert Ready!\n");
|
||||
}
|
||||
|
||||
WebServerThread *webServerThread;
|
||||
@@ -181,6 +193,8 @@ void initWebServer()
|
||||
{
|
||||
DEBUG_MSG("Initializing Web Server ...\n");
|
||||
|
||||
#if 0
|
||||
// this seems to be a copypaste dup of taskCreateCert
|
||||
prefs.begin("MeshtasticHTTPS", false);
|
||||
|
||||
size_t pkLen = prefs.getBytesLength("PK");
|
||||
@@ -211,6 +225,7 @@ void initWebServer()
|
||||
} else {
|
||||
DEBUG_MSG("Web Server started without SSL keys! How did this happen?\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// We can now use the new certificate to setup our server as usual.
|
||||
secureServer = new HTTPSServer(cert);
|
||||
@@ -218,14 +233,16 @@ void initWebServer()
|
||||
|
||||
registerHandlers(insecureServer, secureServer);
|
||||
|
||||
DEBUG_MSG("Starting Web Servers...\n");
|
||||
secureServer->start();
|
||||
if(secureServer) {
|
||||
DEBUG_MSG("Starting Secure Web Server...\n");
|
||||
secureServer->start();
|
||||
}
|
||||
DEBUG_MSG("Starting Insecure Web Server...\n");
|
||||
insecureServer->start();
|
||||
if (secureServer->isRunning() && insecureServer->isRunning()) {
|
||||
DEBUG_MSG("HTTP and HTTPS Web Servers Ready! :-) \n");
|
||||
isWebServerReady = 1;
|
||||
if (insecureServer->isRunning()) {
|
||||
DEBUG_MSG("Web Servers Ready! :-) \n");
|
||||
isWebServerReady = true;
|
||||
} else {
|
||||
DEBUG_MSG("HTTP and HTTPS Web Servers Failed! ;-( \n");
|
||||
DEBUG_MSG("Web Servers Failed! ;-( \n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
void initWebServer();
|
||||
void createSSLCert();
|
||||
|
||||
|
||||
void handleWebResponse();
|
||||
|
||||
|
||||
class WebServerThread : private concurrency::OSThread
|
||||
{
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "NodeDB.h"
|
||||
#include "concurrency/Periodic.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "mqtt/MQTT.h"
|
||||
#include "mesh/http/WebServer.h"
|
||||
#include "mesh/wifi/WiFiServerAPI.h"
|
||||
#include "target_specific.h"
|
||||
@@ -9,6 +11,8 @@
|
||||
#include <ESPmDNS.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
static void WiFiEvent(WiFiEvent_t event);
|
||||
|
||||
// DNS Server for the Captive Portal
|
||||
@@ -23,6 +27,47 @@ bool forcedSoftAP = 0;
|
||||
|
||||
bool APStartupComplete = 0;
|
||||
|
||||
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning
|
||||
|
||||
// FIXME, veto light sleep if we have a TCP server running
|
||||
#if 0
|
||||
class WifiSleepObserver : public Observer<uint32_t> {
|
||||
protected:
|
||||
|
||||
/// Return 0 if sleep is okay
|
||||
virtual int onNotify(uint32_t newValue) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
static WifiSleepObserver wifiSleepObserver;
|
||||
//preflightSleepObserver.observe(&preflightSleep);
|
||||
#endif
|
||||
|
||||
static int32_t reconnectWiFi()
|
||||
{
|
||||
if (radioConfig.has_preferences && needReconnect) {
|
||||
|
||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||
|
||||
if (!*wifiPsw) // Treat empty password as no password
|
||||
wifiPsw = NULL;
|
||||
|
||||
if (*wifiName) {
|
||||
needReconnect = false;
|
||||
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point");
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
}
|
||||
}
|
||||
|
||||
return 30 * 1000; // every 30 seconds
|
||||
}
|
||||
|
||||
static Periodic *wifiReconnect;
|
||||
|
||||
bool isSoftAPForced()
|
||||
{
|
||||
return forcedSoftAP;
|
||||
@@ -32,25 +77,15 @@ bool isWifiAvailable()
|
||||
{
|
||||
// If wifi status is connected, return true regardless of the radio configuration.
|
||||
if (isSoftAPForced()) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||
|
||||
// strcpy(radioConfig.preferences.wifi_ssid, "meshtastic");
|
||||
// strcpy(radioConfig.preferences.wifi_password, "meshtastic!");
|
||||
|
||||
// strcpy(radioConfig.preferences.wifi_ssid, "meshtasticAdmin");
|
||||
// strcpy(radioConfig.preferences.wifi_password, "12345678");
|
||||
|
||||
// radioConfig.preferences.wifi_ap_mode = true;
|
||||
// radioConfig.preferences.wifi_ap_mode = false;
|
||||
|
||||
if (*wifiName && *wifiPsw) {
|
||||
return 1;
|
||||
if (*wifiName) {
|
||||
return true;
|
||||
} else {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,28 +110,48 @@ void deinitWifi()
|
||||
}
|
||||
}
|
||||
|
||||
// Startup WiFi
|
||||
void initWifi(bool forceSoftAP)
|
||||
static void onNetworkConnected()
|
||||
{
|
||||
if (!APStartupComplete) {
|
||||
// Start web server
|
||||
DEBUG_MSG("... Starting network services\n");
|
||||
|
||||
if (forceSoftAP) {
|
||||
// do nothing
|
||||
// DEBUG_MSG("----- Forcing SoftAP\n");
|
||||
} else {
|
||||
if (isWifiAvailable() == 0) {
|
||||
return;
|
||||
// start mdns
|
||||
if (!MDNS.begin("Meshtastic")) {
|
||||
DEBUG_MSG("Error setting up MDNS responder!\n");
|
||||
} else {
|
||||
DEBUG_MSG("mDNS responder started\n");
|
||||
DEBUG_MSG("mDNS Host: Meshtastic.local\n");
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("https", "tcp", 443);
|
||||
}
|
||||
}
|
||||
|
||||
initWebServer();
|
||||
initApiServer();
|
||||
|
||||
APStartupComplete = true;
|
||||
}
|
||||
|
||||
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
||||
if(mqtt)
|
||||
mqtt->reconnect();
|
||||
}
|
||||
|
||||
// Startup WiFi
|
||||
bool initWifi(bool forceSoftAP)
|
||||
{
|
||||
forcedSoftAP = forceSoftAP;
|
||||
|
||||
createSSLCert();
|
||||
|
||||
if (radioConfig.has_preferences || forceSoftAP) {
|
||||
if ((radioConfig.has_preferences && radioConfig.preferences.wifi_ssid[0]) || forceSoftAP) {
|
||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||
|
||||
if ((*wifiName && *wifiPsw) || forceSoftAP) {
|
||||
createSSLCert();
|
||||
|
||||
if (!*wifiPsw) // Treat empty password as no password
|
||||
wifiPsw = NULL;
|
||||
|
||||
if (*wifiName || forceSoftAP) {
|
||||
if (forceSoftAP) {
|
||||
|
||||
DEBUG_MSG("Forcing SoftAP\n");
|
||||
@@ -153,33 +208,17 @@ void initWifi(bool forceSoftAP)
|
||||
},
|
||||
WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
|
||||
|
||||
DEBUG_MSG("JOINING WIFI: ssid=%s\n", wifiName);
|
||||
if (WiFi.begin(wifiName, wifiPsw) == WL_CONNECTED) {
|
||||
DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.localIP().toString().c_str());
|
||||
} else {
|
||||
DEBUG_MSG("Started Joining WIFI\n");
|
||||
}
|
||||
DEBUG_MSG("JOINING WIFI soon: ssid=%s\n", wifiName);
|
||||
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
|
||||
}
|
||||
}
|
||||
|
||||
if (!MDNS.begin("Meshtastic")) {
|
||||
DEBUG_MSG("Error setting up MDNS responder!\n");
|
||||
|
||||
while (1) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
DEBUG_MSG("mDNS responder started\n");
|
||||
DEBUG_MSG("mDNS Host: Meshtastic.local\n");
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("https", "tcp", 443);
|
||||
|
||||
} else
|
||||
return true;
|
||||
} else {
|
||||
DEBUG_MSG("Not using WIFI\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Called by the Espressif SDK to
|
||||
static void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
@@ -193,10 +232,10 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
DEBUG_MSG("Completed scan for access points\n");
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
DEBUG_MSG("WiFi client started\n");
|
||||
DEBUG_MSG("WiFi station started\n");
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_STOP:
|
||||
DEBUG_MSG("WiFi clients stopped\n");
|
||||
DEBUG_MSG("WiFi station stopped\n");
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_CONNECTED:
|
||||
DEBUG_MSG("Connected to access point\n");
|
||||
@@ -205,7 +244,7 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
DEBUG_MSG("Disconnected from WiFi access point\n");
|
||||
// Event 5
|
||||
|
||||
reconnectWiFi();
|
||||
needReconnect = true;
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
|
||||
DEBUG_MSG("Authentication mode of access point has changed\n");
|
||||
@@ -213,18 +252,7 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
DEBUG_MSG("Obtained IP address: \n");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
if (!APStartupComplete) {
|
||||
// Start web server
|
||||
DEBUG_MSG("... Starting network services\n");
|
||||
initWebServer();
|
||||
initApiServer();
|
||||
|
||||
APStartupComplete = true;
|
||||
} else {
|
||||
DEBUG_MSG("... Not starting network services (They're already running)\n");
|
||||
}
|
||||
|
||||
onNetworkConnected();
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_LOST_IP:
|
||||
DEBUG_MSG("Lost IP address and IP address is reset to 0\n");
|
||||
@@ -244,18 +272,7 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
case SYSTEM_EVENT_AP_START:
|
||||
DEBUG_MSG("WiFi access point started\n");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
|
||||
if (!APStartupComplete) {
|
||||
// Start web server
|
||||
DEBUG_MSG("... Starting network services\n");
|
||||
initWebServer();
|
||||
initApiServer();
|
||||
|
||||
APStartupComplete = true;
|
||||
} else {
|
||||
DEBUG_MSG("... Not starting network services (They're already running)\n");
|
||||
}
|
||||
|
||||
onNetworkConnected();
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_STOP:
|
||||
DEBUG_MSG("WiFi access point stopped\n");
|
||||
@@ -302,23 +319,6 @@ void handleDNSResponse()
|
||||
}
|
||||
}
|
||||
|
||||
void reconnectWiFi()
|
||||
{
|
||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||
|
||||
if (radioConfig.has_preferences) {
|
||||
|
||||
if (*wifiName && *wifiPsw) {
|
||||
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point");
|
||||
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getWifiDisconnectReason()
|
||||
{
|
||||
return wifiDisconnectReason;
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
void initWifi(bool forceSoftAP);
|
||||
/// @return true if wifi is now in use
|
||||
bool initWifi(bool forceSoftAP);
|
||||
|
||||
void deinitWifi();
|
||||
|
||||
bool isWifiAvailable();
|
||||
|
||||
void handleDNSResponse();
|
||||
|
||||
void reconnectWiFi();
|
||||
|
||||
bool isSoftAPForced();
|
||||
|
||||
uint8_t getWifiDisconnectReason();
|
||||
|
||||
@@ -18,7 +18,7 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc
|
||||
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize);
|
||||
if (!pb_encode(&stream, fields, src_struct)) {
|
||||
DEBUG_MSG("Panic: can't encode protobuf reason='%s', reason=%s\n", PB_GET_ERROR(&stream));
|
||||
DEBUG_MSG("Panic: can't encode protobuf reason='%s'\n", PB_GET_ERROR(&stream));
|
||||
assert(0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options
|
||||
} else {
|
||||
return stream.bytes_written;
|
||||
@@ -30,7 +30,7 @@ bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msg
|
||||
{
|
||||
pb_istream_t stream = pb_istream_from_buffer(srcbuf, srcbufsize);
|
||||
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||
DEBUG_MSG("Error: can't decode protobuf reason='%s', pb_msgdesc 0x%p, reason=%s\n", PB_GET_ERROR(&stream), fields);
|
||||
DEBUG_MSG("Error: can't decode protobuf reason='%s', pb_msgdesc 0x%p\n", PB_GET_ERROR(&stream), fields);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "WiFiServerAPI.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
@@ -26,19 +25,6 @@ WiFiServerAPI::~WiFiServerAPI()
|
||||
// FIXME - delete this if the client dropps the connection!
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void WiFiServerAPI::onConnectionChanged(bool connected)
|
||||
{
|
||||
// FIXME - we really should be doing global reference counting to see if anyone is currently using serial or wifi and if so,
|
||||
// block sleep
|
||||
|
||||
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
/// override close to also shutdown the TCP link
|
||||
void WiFiServerAPI::close()
|
||||
{
|
||||
@@ -46,6 +32,12 @@ void WiFiServerAPI::close()
|
||||
StreamAPI::close();
|
||||
}
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
bool WiFiServerAPI::checkIsConnected()
|
||||
{
|
||||
return client.connected();
|
||||
}
|
||||
|
||||
int32_t WiFiServerAPI::runOnce()
|
||||
{
|
||||
if (client.connected()) {
|
||||
@@ -57,6 +49,13 @@ int32_t WiFiServerAPI::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
/// If an api server is running, we try to spit out debug 'serial' characters there
|
||||
void WiFiServerPort::debugOut(char c)
|
||||
{
|
||||
if (apiPort && apiPort->openAPI)
|
||||
apiPort->openAPI->debugOut(c);
|
||||
}
|
||||
|
||||
#define MESHTASTIC_PORTNUM 4403
|
||||
|
||||
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM), concurrency::OSThread("ApiServer") {}
|
||||
|
||||
@@ -21,10 +21,14 @@ class WiFiServerAPI : public StreamAPI
|
||||
virtual void close();
|
||||
|
||||
protected:
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
/// We override this method to prevent publishing EVENT_SERIAL_CONNECTED/DISCONNECTED for wifi links (we want the board to
|
||||
/// stay in the POWERED state to prevent disabling wifi)
|
||||
virtual void onConnectionChanged(bool connected) {}
|
||||
|
||||
virtual int32_t runOnce(); // Check for dropped client connections
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -44,6 +48,10 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
|
||||
|
||||
void init();
|
||||
|
||||
/// If an api server is running, we try to spit out debug 'serial' characters there
|
||||
static void debugOut(char c);
|
||||
|
||||
protected:
|
||||
int32_t runOnce();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "MQTT.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "main.h"
|
||||
#include "mesh/Channels.h"
|
||||
#include "mesh/Router.h"
|
||||
#include "mesh/generated/mqtt.pb.h"
|
||||
#include "sleep.h"
|
||||
#include <WiFi.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -57,33 +59,45 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient)
|
||||
mqtt = this;
|
||||
|
||||
pubSub.setCallback(mqttCallback);
|
||||
|
||||
// preflightSleepObserver.observe(&preflightSleep);
|
||||
}
|
||||
|
||||
void MQTT::reconnect()
|
||||
{
|
||||
// pubSub.setServer("devsrv.ezdevice.net", 1883); or 192.168.10.188
|
||||
const char *serverAddr = "mqtt.meshtastic.org"; // default hostname
|
||||
if (wantsLink()) {
|
||||
const char *serverAddr = "mqtt.meshtastic.org"; // default hostname
|
||||
int serverPort = 1883; // default server port
|
||||
|
||||
if (*radioConfig.preferences.mqtt_server)
|
||||
serverAddr = radioConfig.preferences.mqtt_server; // Override the default
|
||||
if (*radioConfig.preferences.mqtt_server)
|
||||
serverAddr = radioConfig.preferences.mqtt_server; // Override the default
|
||||
|
||||
pubSub.setServer(serverAddr, 1883);
|
||||
String server = String(serverAddr);
|
||||
int delimIndex = server.indexOf(':');
|
||||
if (delimIndex > 0) {
|
||||
String port = server.substring(delimIndex + 1, server.length());
|
||||
server[delimIndex] = 0;
|
||||
serverPort = port.toInt();
|
||||
serverAddr = server.c_str();
|
||||
}
|
||||
pubSub.setServer(serverAddr, serverPort);
|
||||
|
||||
DEBUG_MSG("Connecting to MQTT server\n", serverAddr);
|
||||
auto myStatus = (statusTopic + owner.id);
|
||||
bool connected = pubSub.connect(owner.id, "meshdev", "large4cats", myStatus.c_str(), 1, true, "offline");
|
||||
if (connected) {
|
||||
DEBUG_MSG("MQTT connected\n");
|
||||
enabled = true; // Start running background process again
|
||||
runASAP = true;
|
||||
DEBUG_MSG("Connecting to MQTT server %s, port: %d\n", serverAddr, serverPort);
|
||||
auto myStatus = (statusTopic + owner.id);
|
||||
bool connected = pubSub.connect(owner.id, "meshdev", "large4cats", myStatus.c_str(), 1, true, "offline");
|
||||
if (connected) {
|
||||
DEBUG_MSG("MQTT connected\n");
|
||||
enabled = true; // Start running background process again
|
||||
runASAP = true;
|
||||
|
||||
/// FIXME, include more information in the status text
|
||||
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
|
||||
DEBUG_MSG("published %d\n", ok);
|
||||
/// FIXME, include more information in the status text
|
||||
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
|
||||
DEBUG_MSG("published %d\n", ok);
|
||||
|
||||
sendSubscriptions();
|
||||
} else
|
||||
DEBUG_MSG("Failed to contact MQTT server...\n");
|
||||
sendSubscriptions();
|
||||
} else
|
||||
DEBUG_MSG("Failed to contact MQTT server...\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MQTT::sendSubscriptions()
|
||||
@@ -140,6 +154,7 @@ int32_t MQTT::runOnce()
|
||||
pubSub.disconnect();
|
||||
}
|
||||
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // Suppress entering light sleep (because that would turn off bluetooth)
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ class MQTT : private concurrency::OSThread
|
||||
WiFiClient mqttClient;
|
||||
PubSubClient pubSub;
|
||||
|
||||
// instead we supress sleep from our runOnce() callback
|
||||
// CallbackObserver<MQTT, void *> preflightSleepObserver = CallbackObserver<MQTT, void *>(this, &MQTT::preflightSleepCb);
|
||||
|
||||
public:
|
||||
MQTT();
|
||||
|
||||
@@ -32,6 +35,10 @@ class MQTT : private concurrency::OSThread
|
||||
*/
|
||||
void onSend(const MeshPacket &mp, ChannelIndex chIndex);
|
||||
|
||||
/** Attempt to connect to server if necessary
|
||||
*/
|
||||
void reconnect();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce();
|
||||
|
||||
@@ -40,10 +47,6 @@ class MQTT : private concurrency::OSThread
|
||||
*/
|
||||
bool wantsLink() const;
|
||||
|
||||
/** Attempt to connect to server if necessary
|
||||
*/
|
||||
void reconnect();
|
||||
|
||||
/** Tell the server what subscriptions we want (based on channels.downlink_enabled)
|
||||
*/
|
||||
void sendSubscriptions();
|
||||
@@ -53,6 +56,9 @@ class MQTT : private concurrency::OSThread
|
||||
|
||||
/// Called when a new publish arrives from the MQTT server
|
||||
void onPublish(char *topic, byte *payload, unsigned int length);
|
||||
|
||||
/// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server
|
||||
// int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; }
|
||||
};
|
||||
|
||||
void mqttInit();
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
static bool pinShowing;
|
||||
static uint32_t doublepressed;
|
||||
|
||||
static bool bluetoothActive;
|
||||
|
||||
static void startCb(uint32_t pin)
|
||||
{
|
||||
pinShowing = true;
|
||||
@@ -52,23 +54,27 @@ void updateBatteryLevel(uint8_t level)
|
||||
|
||||
void deinitBLE()
|
||||
{
|
||||
// DEBUG_MSG("Shutting down bluetooth\n");
|
||||
// ble_gatts_show_local();
|
||||
if (bluetoothActive) {
|
||||
bluetoothActive = false;
|
||||
|
||||
// FIXME - do we need to dealloc things? - what needs to stay alive across light sleep?
|
||||
auto ret = nimble_port_stop();
|
||||
assert(ret == ESP_OK);
|
||||
// DEBUG_MSG("Shutting down bluetooth\n");
|
||||
// ble_gatts_show_local();
|
||||
|
||||
nimble_port_deinit(); // teardown nimble datastructures
|
||||
// FIXME - do we need to dealloc things? - what needs to stay alive across light sleep?
|
||||
auto ret = nimble_port_stop();
|
||||
assert(ret == ESP_OK);
|
||||
|
||||
// DEBUG_MSG("BLE port_deinit done\n");
|
||||
nimble_port_deinit(); // teardown nimble datastructures
|
||||
|
||||
ret = esp_nimble_hci_and_controller_deinit();
|
||||
assert(ret == ESP_OK);
|
||||
// DEBUG_MSG("BLE port_deinit done\n");
|
||||
|
||||
// DEBUG_MSG("BLE task exiting\n");
|
||||
ret = esp_nimble_hci_and_controller_deinit();
|
||||
assert(ret == ESP_OK);
|
||||
|
||||
DEBUG_MSG("Done shutting down bluetooth\n");
|
||||
// DEBUG_MSG("BLE task exiting\n");
|
||||
|
||||
DEBUG_MSG("Done shutting down bluetooth\n");
|
||||
}
|
||||
}
|
||||
|
||||
void loopBLE()
|
||||
@@ -479,6 +485,8 @@ void disablePin()
|
||||
doublepressed = millis();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This routine is called multiple times, once each time we come back from sleep
|
||||
void reinitBluetooth()
|
||||
{
|
||||
@@ -536,10 +544,10 @@ void reinitBluetooth()
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(ble_host_task);
|
||||
bluetoothActive = true;
|
||||
}
|
||||
|
||||
bool bluetoothOn;
|
||||
bool firstTime = 1;
|
||||
|
||||
// Enable/disable bluetooth.
|
||||
void setBluetoothEnable(bool on)
|
||||
@@ -549,32 +557,15 @@ void setBluetoothEnable(bool on)
|
||||
|
||||
bluetoothOn = on;
|
||||
if (on) {
|
||||
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
|
||||
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
|
||||
reinitBluetooth();
|
||||
|
||||
// Don't try to reconnect wifi before bluetooth is configured.
|
||||
// WiFi is initialized from main.cpp in setup() .
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
} else {
|
||||
#ifndef NO_ESP32
|
||||
initWifi(0);
|
||||
#endif
|
||||
if (!initWifi(0)) // if we are using wifi, don't turn on bluetooth also
|
||||
{
|
||||
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
|
||||
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
|
||||
reinitBluetooth();
|
||||
}
|
||||
} else {
|
||||
|
||||
/*
|
||||
// If WiFi is in use, disable shutting down the radio.
|
||||
if (isWifiAvailable()) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// shutdown wifi
|
||||
#ifndef NO_ESP32
|
||||
deinitWifi();
|
||||
#endif
|
||||
|
||||
// We have to totally teardown our bluetooth objects to prevent leaks
|
||||
deinitBLE();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user