Compare commits

..

76 Commits

Author SHA1 Message Date
Ben Meadors
f5b8c17dbf Merge pull request #1950 from code8buster/1.2-legacy
1.2-legacy version pinning
2022-11-16 13:44:50 -06:00
code8buster
df3e3b747e readme format 2022-11-16 13:52:25 -05:00
code8buster
c2a2ce0b4e Add git repos as libdeps for libs no longer present in package registry, update README.md 2022-11-15 21:40:11 -05:00
Ben Meadors
0adc5ce3de Bump version for release 2022-05-29 18:55:34 -05:00
Thomas Göttgens
1d5e079fa2 Merge pull request #1476 from meshtastic/1.2-ubxreset
Forgot a part of the 1.3 fix
2022-05-30 00:19:29 +02:00
Thomas Göttgens
33fac6d0f5 Forgot a part of the 1.3 fix 2022-05-30 00:05:40 +02:00
Thomas Göttgens
8e8158ebbc Merge pull request #1458 from meshtastic/1.2-ubxreset
ask for factory reset if GPS does not talk to us.
2022-05-18 17:37:27 +01:00
Thomas Göttgens
a9fcc775d9 Merge branch '1.2-ubxreset' of github.com:meshtastic/Meshtastic-device into 1.2-legacy 2022-05-18 18:25:57 +02:00
Thomas Göttgens
cf465a3d34 fixed return for NRF52 2022-05-18 18:25:12 +02:00
Thomas Göttgens
6520c51b66 Merge branch '1.2-legacy' of github.com:meshtastic/Meshtastic-device into 1.2-legacy 2022-05-18 18:08:04 +02:00
Thomas Göttgens
98552b6d9d Merge branch '1.2-legacy' into 1.2-ubxreset 2022-05-18 17:07:53 +01:00
Thomas Göttgens
7f9c07ae37 ask for factory reset if GPS does not talk to us. 2022-05-18 18:06:53 +02:00
Thomas Göttgens
bfd97558d4 Merge pull request #1456 from meshtastic/1.2-buildfix
1.2 buildfix
2022-05-18 15:22:32 +01:00
Thomas Göttgens
44159f75f1 Always send the first command 2022-05-18 15:58:06 +02:00
Thomas Göttgens
dfa9c32665 faster bootup without GPS 2022-05-18 13:05:11 +02:00
Thomas Göttgens
c600135b70 Merge pull request #1455 from meshtastic/1.2-t-echo
fix GPS and Buttons on T-Echo and log UBX (1.2)
2022-05-17 20:11:32 +01:00
Thomas Göttgens
179a2624a1 Merge branch '1.2-t-echo' of github.com:meshtastic/Meshtastic-device into 1.2-legacy 2022-05-17 21:02:35 +02:00
Thomas Göttgens
3fded9aaa9 don't be too smart 2022-05-17 21:02:00 +02:00
Thomas Göttgens
f423d943a8 Merge branch '1.2-legacy' into 1.2-t-echo 2022-05-17 18:56:27 +01:00
Thomas Göttgens
f251727524 wrong header file 2022-05-17 19:47:59 +02:00
Thomas Göttgens
f3cc732e7d Print error codes and returns during UBX config 2022-05-17 19:44:41 +02:00
Thomas Göttgens
8d74c41802 switch GPS back to 9600 baud, seems to work better now we only use the 2 sentences 2022-05-17 18:57:42 +02:00
Thomas Göttgens
89f7968ca2 don't wake t-echo through the touch button 2022-05-17 13:03:14 +02:00
Thomas Göttgens
3b2375a27b Merge pull request #1452 from meshtastic/1.2-buildfix
Fix building with PIO6
2022-05-17 10:24:13 +01:00
Thomas Göttgens
959962530b missed one ... 2022-05-17 11:11:47 +02:00
Thomas Göttgens
77816f8f68 Fix building with PIO6 2022-05-17 10:58:44 +02:00
Ben Meadors
ee8e544ce2 Added dr-dev 2022-05-07 21:04:39 -05:00
Ben Meadors
887e6fd761 Added meshtastic-dr-dev to release 2022-05-07 20:04:09 -05:00
Ben Meadors
d06aa73947 Added meshtastic-dr-dev to ci action 2022-05-07 20:02:58 -05:00
code8buster
72bfee34ee Disaster Radio dev board initial support (#1443)
* Initial pin redefs for Disasterradio's prototype pcb

* Initializes E22-900M30S correctly, seems to be ready to work

* Add new macros for upstream merge

* Cleaning up stray experiment

That was silly, what was I even thinking? Late evening coding mistakes.
2022-05-07 20:00:01 -05:00
Ben Meadors
fc48fcde96 Bump version for release 2022-05-04 07:59:25 -05:00
Thomas Göttgens
f0965e2ac4 Merge pull request #1431 from meshtastic/1.2-techo
Backport T-Echo fix for GPS and Reset Button to 1.2
2022-05-04 09:41:01 +01:00
Thomas Göttgens
7c253bfc3c Backport T-Echo fix for GPS and Reset Button to 1.2 2022-05-04 09:58:35 +02:00
Ben Meadors
ba894ae95b Use sx126x macro (#1424) 2022-04-30 07:08:59 -05:00
Ben Meadors
9879494fc6 Bump version for release 2022-04-29 07:23:08 -05:00
Ben Meadors
5088940751 Set tx/rx en correctly as well as rf ant switch (#1420) 2022-04-28 20:11:03 -05:00
Ben Meadors
888af31d4f Add extensions to gitignore 2022-04-28 06:58:59 -05:00
mkinney
3ddd74edf6 Update version.properties 2022-04-27 13:29:42 -07:00
Mike Kinney
186d7f7d33 Merge branch '1.2-legacy' of github.com:meshtastic/Meshtastic-device into 1.2-legacy 2022-04-27 13:28:20 -07:00
Mike Kinney
456f8ab7e8 ensure the screen displays properly 2022-04-27 13:28:13 -07:00
mkinney
d551c17546 Update version.properties
add nano_g1
2022-04-27 11:55:08 -07:00
Mike Kinney
af4027e8c8 needed to add nano_g1 to 1.2 main_matrix 2022-04-27 11:52:02 -07:00
Mike Kinney
3df0fdd239 need that submodule 2022-04-27 11:42:13 -07:00
Mike Kinney
8510ef3ad0 add nano-g1 to build 2022-04-27 10:57:32 -07:00
neilhao
ee419f8b9b add nano g1 (#1351)
* add nano g1

* Update platformio.ini

* Update configuration.h

* Revert platformio.ini to previous state

* Update configuration.h

* Update platformio.ini

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2022-04-27 10:56:06 -07:00
Ben Meadors
ab959ded0e Bump to 1.2.60 for release 2022-04-26 06:39:31 -05:00
Ben Meadors
2a76a5527a Fix execution halt in nrf devices on assert and add --reboot support on nrf (#1397)
* Fix execution halt in nrf devices on assert

* Peg espressif platform to 3.5.0

* Add reboot to nrf52 devices
2022-04-25 16:48:28 +10:00
Ben Meadors
58d91f0a4b Add battery pin to meshtastic-diy (#1319)
* Add battery pin to meshtastic-diy

* Adc multiplier
2022-03-24 19:18:14 -05:00
Thomas Göttgens
e09aafa13f Merge pull request #1313 from meshtastic/1.2-fix-rotary-encoder
Rotary Encoder Update
2022-03-21 15:43:58 +01:00
Thomas Göttgens
aca95248ee Rotary Encoder Update - play nice with Onebutton and small bugfix - also switches screen on when any input is processed by the broker 2022-03-21 15:16:25 +01:00
mkinney
d81c1c08ee Update version.properties 2022-03-17 13:47:36 -07:00
mkinney
317ce2c9cd Merge pull request #1303 from mkinney/fix_for_dupl_mac_addr
re-init so the duplicate mac address issue on NRF devices will be fixed
2022-03-17 13:47:11 -07:00
Mike Kinney
b2827597fd re-init so the duplicate mac address issue on NRF devices will be fixed 2022-03-17 20:32:15 +00:00
mkinney
6af182228c Update version.properties 2022-03-17 11:51:52 -07:00
mkinney
1246c7bb1e Merge pull request #1301 from mkinney/nrf_factory_reset
try to reset values on nrf using nodeDB methods
2022-03-17 11:49:41 -07:00
Mike Kinney
e6731e28c1 try removing the /prefs dir 2022-03-17 18:33:30 +00:00
Mike Kinney
d57ac39b02 move the factory reset stuff above the ble bonds 2022-03-17 18:08:39 +00:00
Mike Kinney
67bc6b1419 try to reset values on nrf using nodeDB methods 2022-03-17 17:49:02 +00:00
Thomas Göttgens
d328823c03 Destroy HTTPS Client on unpack error (#1279)
This gives you more than one try to update the embedded Web IF without rebooting the device. This can also be cherry-picked for 1.3
2022-03-10 08:28:06 -06:00
Sacha Weatherstone
7178d3a2fd Sync fix 2022-03-10 09:03:31 +11:00
Ben Meadors
a0f60f1d07 Putting this test back in 2022-03-06 08:18:20 -06:00
Ben Meadors
b177313e2d Removing test simulator for now 2022-03-06 07:57:04 -06:00
Ben Meadors
53d47146b2 Attempt to push artifacts to another repo 2022-03-06 07:38:55 -06:00
mkinney
f7c6955736 Update version.properties 2022-03-01 16:25:58 -08:00
mkinney
9a87e1b53e Merge pull request #1266 from mkinney/bug_fixes
remove assert; revert a change that cpplint reported as a warning
2022-03-01 16:11:34 -08:00
Mike Kinney
f1478a7c93 remove assert; revert a change that cpplint reported as a warning 2022-03-02 00:00:31 +00:00
Jm Casler
8fd5d83980 Merge branch '1.2-legacy' of https://github.com/meshtastic/Meshtastic-device into 1.2-legacy 2022-02-27 07:30:00 -08:00
Jm Casler
5895aaa259 Revert "updating proto submodule to latest"
This reverts commit 682f988c2a.
2022-02-27 07:29:31 -08:00
Jm Casler
1787712a5a Revert "updating proto submodule to latest"
This reverts commit d56f8c631b.
2022-02-27 07:29:25 -08:00
Ben Meadors
596a73c0a0 Peg protos to 1.2 ref and bump version for release 2022-02-27 09:27:56 -06:00
Jm Casler
d56f8c631b updating proto submodule to latest 2022-02-26 21:22:31 -08:00
Jm Casler
682f988c2a updating proto submodule to latest 2022-02-26 21:09:18 -08:00
Ben Meadors
ce20a2b566 Github action to allow 1.2-legacy release 2022-02-26 13:04:25 -06:00
joshpirihi
d0fc836f0b Position packets generated locally should be sent to the phone too (#1242)
* Position packets generated locally should be sent to the phone too
2022-02-26 07:37:23 -06:00
Ben Meadors
d542267e4a Add after-checks for PR checks 2022-02-25 17:06:44 -06:00
Ben Meadors
756317e7e0 Legacy CI fix 2022-02-25 16:52:54 -06:00
164 changed files with 2884 additions and 3912 deletions

View File

@@ -1,76 +0,0 @@
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: dropdown
id: category
attributes:
label: Category
description: How would you catagorize this issue?
multiple: true
options:
- Hardware Compatibility
- BLE
- Serial
- WiFi
- Other
validations:
required: true
- type: dropdown
id: hardware
attributes:
label: Hardware
description: What hardware are you encountering this issue on?
multiple: true
options:
- Not Applicable
- T-Beam
- T-Beam 0.7
- T-Lora v1
- T-Lora v1.3
- T-Lora v2 1.6
- T-Echo
- Rak4631
- Rak11200
- Heltec v1
- Heltec v2
- Heltec v2.1
- Relay v1
- Relay v2
- DIY
- Other
validations:
required: true
- type: input
id: version
attributes:
label: Firmware Version
description: This can be found on the device's screen or via one of the apps.
placeholder: x.x.x.yyyyyyy
validations:
required: true
- type: textarea
id: body
attributes:
label: Description
description: Please provide details on what steps you performed for this to happen.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: If you have any log output to help in diagnosing your bug, please provide it here.
render: Shell
validations:
required: false

View File

@@ -0,0 +1,38 @@
---
name: Bug report or feature proposal
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
Please - if you just have a question (i.e. not a bug report or a feature proposal), post in our [forum](https://meshtastic.discourse.group/) instead.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Device info:**
- Device model: [e.g. TBEAM]
- Software Version [e.g. 0.7.8]
**Smartphone information (if relevant):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- App Version [e.g. 0.7.2]
**Additional context**
Add any other context about the problem here.

39
.github/actions/initbuild/action.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: 'Common init'
# WARNING due to https://github.com/actions/runner/issues/646
# this code can't work - must copy and paste into workflows for now because 'uses' is not supported
runs:
using: "composite"
steps:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v1
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools
# We actually want to run this every time
# if: steps.cache-pip.outputs.cache-hit != 'true'
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil
# Don't cache for now because I want to be lazy with portuino updates githashes
# - name: Cache platformio
# uses: actions/cache@v1
# id: cache-platformio # needed in if test
# with:
# path: ~/.platformio
# key: ${{ runner.os }}-platformio
- name: Upgrade platformio
run: |
pio upgrade

View File

@@ -1,8 +1,8 @@
name: Continuous Integration
name: Continuous Integration PR Checks (1.2 Legacy)
on:
# # Triggers the workflow on push but only for the master branch
push:
branches: [ master ]
branches: [ 1.2-legacy ]
paths-ignore:
- '**.md'
- '**.yml'
@@ -10,7 +10,7 @@ on:
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
pull_request_target:
branches: [ master ]
branches: [ 1.2-legacy ]
paths-ignore:
- '**.md'
- '**.yml'
@@ -37,8 +37,9 @@ jobs:
- board: meshtastic-diy-v1
- board: rak4631_5005
- board: rak4631_19003
- board: rak4631_5005_eink
- board: t-echo
- board: nano-g1
- board: meshtastic-dr-dev
runs-on: ubuntu-latest
steps:
@@ -69,14 +70,24 @@ jobs:
- name: Upgrade python tools and install platformio
run: |
python -m pip install --upgrade pip
pip install -U platformio
pip install -U platformio
- name: Upgrade platformio
run: |
pio upgrade
- name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
after-checks:
runs-on: ubuntu-latest
needs: [check]
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
build-esp32:
strategy:
@@ -94,6 +105,8 @@ jobs:
- board: heltec-v2.1
- board: tbeam0.7
- board: meshtastic-diy-v1
- board: nano-g1
- board: meshtastic-dr-dev
runs-on: ubuntu-latest
steps:
@@ -120,7 +133,7 @@ jobs:
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
pip install -U platformio meshtastic adafruit-nrfutil
- name: Upgrade platformio
run: |
@@ -158,12 +171,10 @@ jobs:
build-nrf52:
strategy:
fail-fast: false
max-parallel: 2
matrix:
include:
- board: rak4631_5005
- board: rak4631_19003
- board: rak4631_5005_eink
- board: t-echo
runs-on: ubuntu-latest
@@ -271,16 +282,6 @@ jobs:
release/device-*.sh
release/device-*.bat
retention-days: 90
after-checks:
runs-on: ubuntu-latest
needs: [check]
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
gather-artifacts:
runs-on: ubuntu-latest
@@ -302,7 +303,7 @@ jobs:
id: version
- name: Move files up
run: mv -b -t ./ ./*tbeam-*/littlefs*.bin ./*tbeam-*/system-info.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
run: mv -b -t ./ ./*tbeam-*/spiffs*.bin ./*tbeam-*/system-info.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v2
@@ -334,12 +335,15 @@ jobs:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
path: ./*.elf
retention-days: 90
- name: Create request artifacts
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
uses: gavv/pull-request-artifacts@v1.0.0
with:
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
artifacts-branch: artifacts
artifacts-token: ${{ secrets.ARTIFACTS_TOKEN }}
artifacts-repo: meshtastic/artifacts
artifacts-branch: device
artifacts-dir: pr
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip

View File

@@ -1,13 +1,13 @@
name: Make Release
on:
# Can optionally take parameters from the github UI, more info here https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/#:~:text=You%20can%20now%20create%20workflows,the%20workflow%20is%20run%20on.
workflow_dispatch:
#workflow_dispatch:
# inputs:
# Only want to run if version.properties is bumped in master
push:
branches:
- master
- 1.2-legacy
paths:
- 'version.properties'
@@ -37,7 +37,7 @@ jobs:
# if: steps.cache-pip.outputs.cache-hit != 'true'
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
pip install -U platformio meshtastic adafruit-nrfutil
- name: Upgrade platformio
run: |

1
.gitignore vendored
View File

@@ -29,3 +29,4 @@ __pycache__
venv/
release/
.vscode/extensions.json

1
.gitmodules vendored
View File

@@ -1,6 +1,7 @@
[submodule "proto"]
path = proto
url = https://github.com/meshtastic/Meshtastic-protobufs.git
branch = 1.2-legacy
[submodule "sdk-nrfxlib"]
path = sdk-nrfxlib
url = https://github.com/nrfconnect/sdk-nrfxlib.git

View File

@@ -1,11 +1,8 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide",
"xaver.clang-format"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide",
"xaver.clang-format"
]
}

View File

@@ -10,7 +10,7 @@ RUN cd Meshtastic-device; git submodule update --init --recursive
# only build the simulator
RUN sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' Meshtastic-device/bin/build-all.sh
RUN sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' Meshtastic-device/bin/build-all.sh
RUN sed -i 's/echo "Building Filesystem.*/exit/' Meshtastic-device/bin/build-all.sh
RUN sed -i 's/echo "Building SPIFFS.*/exit/' Meshtastic-device/bin/build-all.sh
RUN . ~/.platformio/penv/bin/activate; cd Meshtastic-device; ./bin/build-all.sh
CMD ["/Meshtastic-device/release/latest/bins/universal/meshtasticd_linux_amd64"]

View File

@@ -1,72 +0,0 @@
## What is Docker used for
Developers can simulate Device hardware by compiling and running
a linux native binary application. If you do not own a Linux
machine, or you just want to separate things, you might want
to run simulator inside a docker container
## The Image
To build docker image, type
`docker build -t meshtastic/device .`
## Usage
To run a container, type
`docker run --rm -p 4403:4403 meshtastic/device`
or, to get an interactive shell on the docker created container:
`docker run -it -p 4403:4403 meshtastic/device bash`
You might want to mount your local development folder:
`docker run -it --mount type=bind,source=/PathToMyProjects/Meshtastic/Meshtastic-device-mybranch,target=/Meshtastic-device-mybranch -p 4403:4403 meshtastic/device bash`
## Build the native application
Linux native application should be built inside the container.
For this you must run container with interactive console
"-it", as seen above.
First, some environment variables need to be set up with command:
`. ~/.platformio/penv/bin/activate`
You also want to make some adjustments in the bin/build-all.sh to conform the amd64 build:
```
sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' bin/build-all.sh
sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' bin/build-all.sh
sed -i 's/echo "Building SPIFFS.*/exit/' bin/build-all.sh
```
You can build amd64 image with command
`bin/build-all.sh`
## Executing the application interactively
The built binary file should be found under name
`release/latest/bins/universal/meshtastic_linux_amd64`.
If this is not the case, you can also use direct program name:
`.pio/build/native/program`
To use python cli against exposed port 4403,
type this in the host machine:
`meshtastic --info --host localhost`
## Stop the container
Run this to get the ID:
`docker ps`
Stop the container with command:
`docker kill <id>`
> Tip: you can just use the first few characters of the ID in docker commands

View File

@@ -3,16 +3,20 @@
[![Continuous Integration](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml/badge.svg)](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml)
![GitHub all releases](https://img.shields.io/github/downloads/meshtastic/meshtastic-device/total)
This branch is End-of-Life.
Requires platformio = 6.0.0
Recommended to add "core_dir = .platformio" to your cloned platformio.ini and use python-virtualenv for compiling this branch. This will keep your system platformio and platform_packages separate.
# Old readme below #
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
Update Instructions
[Using Meshtastic Flasher](https://meshtastic.org/docs/getting-started/meshtastic-flasher)
Manual Method
Update Instructions (docs have versioned up, may no longer apply)
[For ESP32 devices click here](https://meshtastic.org/docs/getting-started/flashing-esp32)
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52)
For developer information and specific building instructions, please see the [developer documentation](https://meshtastic.org/docs/developers)
For developer information and specific building instructions, please see the [developer doccumentation](https://meshtastic.org/docs/developers)

View File

@@ -5,11 +5,11 @@ set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
BOARDS_ESP32="rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1"
BOARDS_ESP32="rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 nano-g1 meshtastic-dr-dev"
#BOARDS_ESP32=tbeam
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo"
BOARDS_NRF52="rak4631_5005 rak4631_19003 t-echo"
#BOARDS_NRF52=""
OUTDIR=release/latest
@@ -76,12 +76,12 @@ do_boards "$BOARDS_NRF52" "true"
pio run --environment native
cp .pio/build/native/program $OUTDIR/bins/universal/meshtasticd_linux_amd64
echo "Building Filesystem for ESP32 targets"
echo "Building SPIFFS for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/littlefs-$VERSION.bin
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin
# keep the bins in archive also
cp $OUTDIR/bins/universal/littlefs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
cp $OUTDIR/bins/universal/spiffs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
echo Updating android bins $OUTDIR/forandroid
rm -rf $OUTDIR/forandroid
@@ -103,9 +103,9 @@ XML
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/littlefs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
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.*
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*
echo BUILT ALL

View File

@@ -34,9 +34,9 @@ echo "Copying ESP32 bin file"
SRCBIN=.pio/build/$1/firmware.bin
cp $SRCBIN $OUTDIR/$basename.bin
echo "Building Filesystem for ESP32 targets"
echo "Building SPIFFS for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/spiffs.bin $OUTDIR/littlefs-$VERSION.bin
cp .pio/build/tbeam/spiffs.bin $OUTDIR/spiffs-$VERSION.bin
cp images/system-info.bin $OUTDIR/system-info.bin
cp bin/device-install.* $OUTDIR

View File

@@ -30,7 +30,7 @@ IF EXIST %FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 921600 erase_flash
%PYTHON% -m esptool --baud 921600 write_flash 0x1000 system-info.bin
for %%f in (littlefs-*.bin) do (
for %%f in (spiffs-*.bin) do (
%PYTHON% -m esptool --baud 921600 write_flash 0x00390000 %%f
)
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME%

View File

@@ -48,7 +48,7 @@ if [ -f "${FILENAME}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin
"$PYTHON" -m esptool write_flash 0x00390000 littlefs-*.bin
"$PYTHON" -m esptool write_flash 0x00390000 spiffs-*.bin
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
else
echo "Invalid file: ${FILENAME}"

View File

@@ -1,51 +0,0 @@
#!/usr/bin/env python3
import getopt
import sys
import os
from littlefs import LittleFS
from pathlib import Path
print( "Building LittleFS image..." )
argList = sys.argv[1:]
arxx = { argList[i]: argList[i+1] for i in range(0, len(argList)-1, 2) }
dataPath = arxx["-c"]
blockSize = int(arxx["-b"])
blockCount = int(arxx["-s"]) / blockSize
cwd = os.getcwd()
os.chdir(dataPath)
fileList = []
dirList = []
for (dirpath, dirnames, filenames) in os.walk('.'):
for f in filenames:
if (f[:1] != '.'):
fileList.append( os.path.join(dirpath, f) )
for d in dirnames:
if (d[:1] != '.'):
dirList.append( os.path.join(dirpath, d) )
fs = LittleFS(block_size=blockSize, block_count=blockCount) # create a 448kB partition
for curDir in dirList:
print( "Creating dir " + curDir )
fs.mkdir( curDir )
for curFile in fileList:
print( "Adding file " + curFile )
with open( curFile, 'rb' ) as f:
data = f.read()
with fs.open( curFile, 'wb') as fh:
fh.write( data )
outName = argList[-1]
os.chdir(cwd)
with open(outName, 'wb') as fh:
fh.write(fs.context.buffer)

View File

@@ -6,13 +6,6 @@ import traceback
import sys
from readprops import readProps
Import("env")
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/bin/mklittlefs.py' )
try:
import littlefs
except ImportError:
env.Execute("$PYTHONEXE -m pip install --user littlefs-python")
Import("projenv")
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"

17
docker.txt Normal file
View File

@@ -0,0 +1,17 @@
To build:
docker build -t meshtastic/device .
To run:
docker run --rm -p 4403:4403 meshtastic/device
or, to get a shell on the docker image:
docker run -it meshtastic/device bash
To use python cli against it:
meshtastic --info --host localhost
To stop:
# run this to get id
docker ps
# tip: you can just use the first few characters of the id in the next command
docker kill <id>

View File

@@ -63,7 +63,7 @@ You probably don't care about this section - skip to the next one.
## Multichannel support
* DONE cleanup the external notification and serial modules
* DONE cleanup the external notification and serial plugins
* non ack version of stress test fails sometimes!
* tx fault test has a bug #734 - * turn off fault 8: https://github.com/meshtastic/Meshtastic-device/issues/734
* DONE move device types into an enum in nodeinfo
@@ -71,7 +71,7 @@ You probably don't care about this section - skip to the next one.
* nrf52 should preserve local time across reset
* cdcacm bug on nrf52: emittx thinks it emitted but client sees nothing. works again later
* nrf52: segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger)
* DONE call RouterModule for *all* packets - not just Router packets
* DONE call RouterPlugin for *all* packets - not just Router packets
* DONE generate channel hash from the name of the channel+the psk (not just one or the other)
* DONE send a hint that can be used to select which channel to try and hash against with each message
* DONE remove deprecated
@@ -79,13 +79,13 @@ You probably don't care about this section - skip to the next one.
* DONE set mynodeinfo.max_channels
* DONE set mynodeinfo.num_bands (formerly num_channels)
* DONE fix sniffing of non Routing packets
* DONE enable remote setttings access by moving settings operations into a regular module (move settings ops out of PhoneAPI)
* DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI)
* DONE move portnum up?
* DONE remove region specific builds from the firmware
* DONE test single channel without python
* DONE Use "default" for name if name is empty
* DONE fix python data packet receiving (nothing showing in log?)
* DONE implement 'get channels' Admin module operation
* DONE implement 'get channels' Admin plugin operation
* DONE use get-channels from python
* DONE use get channels & get settings from android
* DONE use set-channel from python
@@ -98,7 +98,7 @@ You probably don't care about this section - skip to the next one.
* DONE fix setch-fast in python tool
* age out pendingrequests in the python API
* DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection
* DONE combine acks and responses in a single message if possible (do routing module LAST and drop ACK if someone else has already replied)
* DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
* DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
* DONE fix 1.1.50 android debug panel display
* DONE test android channel setting
@@ -118,7 +118,7 @@ You probably don't care about this section - skip to the next one.
* use single byte 'well known' channel names for admin, gpio, etc...
* use presence of gpio channel to enable gpio ops, same for serial etc...
* DONE restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
* DONE add channel restrictions for modules (and restrict routing module to the "control" channel)
* DONE add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
* stress test multi channel
* DONE investigate @mc-hamster report of heap corruption
* DONE use set-user from android
@@ -134,7 +134,7 @@ You probably don't care about this section - skip to the next one.
* allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead
* DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key.
* when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets
* DONE confirm we are still calling the modules for messages inbound from the phone (or generated locally)
* DONE confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
* DONE confirm we are still multi hop routing flood broadcasts
* DONE confirm we are still doing resends on unicast reliable packets
* add history to routed packets: https://meshtastic.discourse.group/t/packet-source-tracking/2764/2
@@ -142,7 +142,7 @@ You probably don't care about this section - skip to the next one.
* DONE move acks into routing
* DONE make all subpackets different versions of data
* DONE move routing control into a data packet
* have phoneapi done via module (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
* have phoneapi done via plugin (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
* use reference counting and dynamic sizing for meshpackets. - use https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 (already used in arduino)
* let multiple PhoneAPI endpoints work at once
* allow multiple simultaneous bluetooth connections (create the bluetooth phoneapi instance dynamically based on client id)
@@ -182,13 +182,13 @@ For app cleanup:
* DONE require a recent python api to talk to these new device loads
* DONE require a recent android app to talk to these new device loads
* DONE fix handleIncomingPosition
* DONE move want_replies handling into modules
* DONE move want_replies handling into plugins
* DONE on android for received positions handle either old or new positions / user messages
* DONE on android side send old or new positions as needed / user messages
* DONE test python side handle new position/user messages
* DONE make a gpio example. --gpiowrb 4 1, --gpiord 0x444, --gpiowatch 0x3ff
* DONE fix position sending to use new module
* DONE Add SinglePortNumModule - as the new most useful baseclass
* DONE fix position sending to use new plugin
* DONE Add SinglePortNumPlugin - as the new most useful baseclass
* DONE move positions into regular data packets (use new app framework)
* DONE move user info into regular data packets (use new app framework)
* DONE test that positions, text messages and user info still work

View File

@@ -26,8 +26,10 @@ default_envs = tbeam
;default_envs = rak4631_5005
;default_envs = rak4631_5005_eink
;default_envs = rak4631_19003
;default_envs = nano-g1
;default_envs = meshtastic-diy-v1
;default_envs = meshtastic-diy-v1.1
;default_envs = meshtastic-dr-dev
; board specific config can be moved to the respective 'variants' file.
; See https://docs.platformio.org/en/latest/projectconf/section_platformio.html#extra-configs
@@ -79,12 +81,11 @@ debug_tool = jlink
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#d90231dedbb2f52bd7a32fb8ed8edec52cf4a8cb ; ESP8266_SSD1306
https://github.com/meshtastic/OneButton.git#3bcba9492d01e2a8a86f46700ab16f96dd2cf1f5 ; OneButton library for non-blocking button debounce
mathertel/OneButton@^2.0.3 ; 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
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
https://github.com/meshtastic/TinyGPSPlus.git
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI
@@ -106,7 +107,7 @@ lib_deps =
build_flags = ${env.build_flags} -Os
# -DRADIOLIB_GODMODE
src_filter = ${env.src_filter} -<portduino/>
build_src_filter = ${env.build_src_filter} -<portduino/>
; Common libs for environmental measurements (not included in native / portduino)
[environmental]
@@ -122,9 +123,9 @@ lib_deps =
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
platform = espressif32
src_filter =
${arduino_base.src_filter} -<nrf52/>
platform = espressif32@3.5.0
build_src_filter =
${arduino_base.build_src_filter} -<nrf52/>
upload_speed = 921600
debug_init_break = tbreak setup
@@ -138,11 +139,10 @@ build_flags =
lib_deps =
${arduino_base.lib_deps}
${environmental.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
https://github.com/lewisxhe/esp32_https_server.git#6900520645c0e974eefcc699b659fa481a36b870
h2zero/NimBLE-Arduino@1.3.6
tobozo/ESP32-targz@^1.1.4
https://github.com/tobozo/ESP32-targz#1.1.4
arduino-libraries/NTPClient#531eff39d9fbc831f3d03f706a161739203fbe2a
lorol/LittleFS_esp32@^1.0.6
# Hmm - this doesn't work yet
# board_build.ldscript = linker/esp32.extram.bss.ld
@@ -179,8 +179,8 @@ board_build.partitions = partition-table.csv
;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_src_filter =
; ${arduino_base.build_src_filter} -<esp32/> -<nrf52/>
; Common settings for NRF52 based targets
[nrf52_base]
@@ -195,8 +195,8 @@ build_flags =
-Isrc/nrf52
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
;-DCFG_DEBUG=3
src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
build_src_filter =
${arduino_base.build_src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32> -<mqtt/>
lib_ignore =
BluetoothOTA
; monitor_port = /dev/ttyACM1
@@ -264,6 +264,3 @@ upload_protocol = jlink
monitor_port = /dev/ttyUSB0
; this board's serial chip can only run at 115200, not faster
monitor_speed = 115200
# For experimenting with RAM sizes
# board_build.ldscript = linker/nrf52840_s140_sim832.ld

2
proto

Submodule proto updated: f6ba3722be...f1476bf2f6

View File

@@ -1,220 +0,0 @@
#include "configuration.h"
#include "concurrency/OSThread.h"
#include "PowerFSM.h"
#include "RadioLibInterface.h"
#include "graphics/Screen.h"
#include "power.h"
#include "buzz.h"
#include <OneButton.h>
#ifndef NO_ESP32
#include "nimble/BluetoothUtil.h"
#endif
namespace concurrency
{
/**
* Watch a GPIO and if we get an IRQ, wake the main thread.
* Use to add wake on button press
*/
void wakeOnIrq(int irq, int mode)
{
attachInterrupt(
irq,
[] {
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
},
FALLING);
}
class ButtonThread : public concurrency::OSThread
{
// Prepare for button presses
#ifdef BUTTON_PIN
OneButton userButton;
#endif
#ifdef BUTTON_PIN_ALT
OneButton userButtonAlt;
#endif
#ifdef BUTTON_PIN_TOUCH
OneButton userButtonTouch;
#endif
static bool shutdown_on_long_stop;
public:
static uint32_t longPressTime;
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
#endif
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed);
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
#endif
userButtonAlt.attachClick(userButtonPressed);
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
#ifdef BUTTON_PIN_TOUCH
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN_TOUCH, INPUT_PULLUP_SENSE);
#endif
userButtonTouch.attachClick(touchPressed);
userButtonTouch.attachDuringLongPress(touchPressedLong);
userButtonTouch.attachDoubleClick(touchDoublePressed);
userButtonTouch.attachLongPressStart(touchPressedLongStart);
userButtonTouch.attachLongPressStop(touchPressedLongStop);
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
#endif
}
protected:
/// If the button is pressed we suppress CPU sleep until release
int32_t runOnce() override
{
canSleep = true; // Assume we should not keep the board awake
#ifdef BUTTON_PIN
userButton.tick();
canSleep &= userButton.isIdle();
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
canSleep &= userButtonAlt.isIdle();
#endif
#ifdef BUTTON_PIN_TOUCH
userButtonTouch.tick();
canSleep &= userButtonTouch.isIdle();
#endif
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
// else DEBUG_MSG("sleep ok\n");
return 5;
}
private:
static void touchPressed()
{
screen->forceDisplay();
DEBUG_MSG("touch press!\n");
}
static void touchDoublePressed()
{
DEBUG_MSG("touch double press!\n");
}
static void touchPressedLong()
{
DEBUG_MSG("touch press long!\n");
}
static void touchDoublePressedLong()
{
DEBUG_MSG("touch double pressed!\n");
}
static void touchPressedLongStart()
{
DEBUG_MSG("touch long press start!\n");
}
static void touchPressedLongStop()
{
DEBUG_MSG("touch long press stop!\n");
}
static void userButtonPressed()
{
// DEBUG_MSG("press!\n");
powerFSM.trigger(EVENT_PRESS);
}
static void userButtonPressedLong()
{
// DEBUG_MSG("Long press!\n");
#ifndef NRF52_SERIES
screen->adjustBrightness();
#endif
// If user button is held down for 5 seconds, shutdown the device.
if (millis() - longPressTime > 5 * 1000) {
#ifdef TBEAM_V10
if (axp192_found == true) {
setLed(false);
power->shutdown();
}
#elif NRF52_SERIES
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
if (!shutdown_on_long_stop) {
screen->startShutdownScreen();
DEBUG_MSG("Shutdown from long press");
playBeep();
ledOff(PIN_LED1);
ledOff(PIN_LED2);
shutdown_on_long_stop = true;
}
#endif
} else {
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
}
}
static void userButtonDoublePressed()
{
#ifndef NO_ESP32
disablePin();
#elif defined(HAS_EINK)
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW);
#endif
}
static void userButtonMultiPressed()
{
#ifndef NO_ESP32
clearNVS();
#endif
#ifdef NRF52_SERIES
clearBonds();
#endif
}
static void userButtonPressedLongStart()
{
DEBUG_MSG("Long press start!\n");
longPressTime = millis();
}
static void userButtonPressedLongStop()
{
DEBUG_MSG("Long press stop!\n");
longPressTime = 0;
if (shutdown_on_long_stop) {
playShutdownMelody();
delay(3000);
power->shutdown();
}
}
};
}

View File

@@ -3,20 +3,20 @@
void fsInit()
{
#ifdef FSCom
if (!FSBegin())
#ifdef FS
if (!FSBegin())
{
DEBUG_MSG("ERROR filesystem mount Failed\n");
assert(0); // FIXME - report failure to phone
}
DEBUG_MSG("Filesystem files:\n");
File dir = FSCom.open("/");
File dir = FS.open("/");
File f = dir.openNextFile();
while (f) {
DEBUG_MSG(" %s\n", f.name());
f.close();
f = dir.openNextFile();
f = dir.openNextFile();
}
#endif
}

View File

@@ -7,22 +7,22 @@
#ifdef PORTDUINO
// Portduino version
#include "PortduinoFS.h"
#define FSCom PortduinoFS
#define FS PortduinoFS
#define FSBegin() true
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#elif !defined(NO_ESP32)
// ESP32 version
#include "LITTLEFS.h"
#define FSCom LITTLEFS
#define FSBegin() FSCom.begin(true)
#include "SPIFFS.h"
#define FS SPIFFS
#define FSBegin() FS.begin(true)
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#else
// NRF52 version
#include "InternalFileSystem.h"
#define FSCom InternalFS
#define FSBegin() FSCom.begin()
#define FS InternalFS
#define FSBegin() FS.begin()
using namespace Adafruit_LittleFS_Namespace;
#endif

View File

@@ -63,7 +63,7 @@ class GPSStatus : public Status
int32_t getLatitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed latitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -75,7 +75,7 @@ class GPSStatus : public Status
int32_t getLongitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed longitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -87,7 +87,7 @@ class GPSStatus : public Status
int32_t getAltitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed altitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -105,7 +105,7 @@ class GPSStatus : public Status
bool matches(const GPSStatus *newStatus) const
{
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n",
newStatus->p.pos_timestamp, p.pos_timestamp);
#endif

View File

@@ -279,6 +279,12 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateON, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
powerFSM.add_transition(&stateSERIAL, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
// Inputbroker
powerFSM.add_transition(&stateLS, &stateON, EVENT_INPUT, NULL, "Input Device");
powerFSM.add_transition(&stateNB, &stateON, EVENT_INPUT, NULL, "Input Device");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_INPUT, NULL, "Input Device");
powerFSM.add_transition(&stateON, &stateON, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");

View File

@@ -20,6 +20,7 @@
#define EVENT_POWER_DISCONNECTED 14
#define EVENT_FIRMWARE_UPDATE 15 // We just received a new firmware update packet from the phone
#define EVENT_SHUTDOWN 16 //force a full shutdown now (not just sleep)
#define EVENT_INPUT 17 // input broker wants something, we need to wake up and enable screen
extern Fsm powerFSM;
extern State statePOWER, stateSERIAL;

View File

@@ -1,38 +0,0 @@
#include "configuration.h"
#include "concurrency/OSThread.h"
#include "main.h"
#include "PowerFSM.h"
#include "power.h"
#include "NodeDB.h"
namespace concurrency
{
/// Wrapper to convert our powerFSM stuff into a 'thread'
class PowerFSMThread : public OSThread
{
public:
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
PowerFSMThread() : OSThread("PowerFSM") {}
protected:
int32_t runOnce() override
{
powerFSM.run_machine();
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
/// cpu for serial rx - FIXME)
auto state = powerFSM.getState();
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
if (powerStatus->getHasUSB()) {
timeLastPowered = millis();
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 &&
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered
powerFSM.trigger(EVENT_SHUTDOWN);
}
return 10;
}
};
}

View File

@@ -140,7 +140,7 @@ int32_t AirTime::runOnce()
}
// Init airtime windows to all 0
for (int i = 0; i < myNodeInfo.air_period_rx_count; i++) {
for (int i = 0; i < PERIODS_TO_LOG; i++) {
this->airtimes.periodTX[i] = 0;
this->airtimes.periodRX[i] = 0;
this->airtimes.periodRX_ALL[i] = 0;

View File

@@ -26,7 +26,7 @@
#define CHANNEL_UTILIZATION_PERIODS 6
#define SECONDS_PER_PERIOD 3600
#define PERIODS_TO_LOG 8
#define PERIODS_TO_LOG 24
#define MINUTES_IN_HOUR 60
#define SECONDS_IN_MINUTE 60
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)

View File

@@ -114,6 +114,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#ifndef TTGO_T_ECHO
#define GPS_UBLOX
#endif
//
// Standard definitions for !ESP32 targets
//
@@ -149,6 +153,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_BAUDRATE 9600
#ifndef GPS_THREAD_INTERVAL
#define GPS_THREAD_INTERVAL 100
#endif
#if defined(TBEAM_V10)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TBEAM
@@ -161,6 +169,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_DIY_V1
#elif defined(DR_DEV)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_DR_DEV
#elif defined(RAK_11200)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_RAK11200
@@ -230,6 +242,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HW_VENDOR HardwareModel_T_ECHO
#elif defined(NANO_G1)
#define HW_VENDOR HardwareModel_NANO_G1
#elif NRF52_SERIES
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN
@@ -242,4 +258,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "variant.h"
#include "RF95Configuration.h"
#include "DebugConfiguration.h"
#include "DebugConfiguration.h"

View File

@@ -1,19 +0,0 @@
#if 0
// Turn off for now
uint32_t axpDebugRead()
{
axp.debugCharging();
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
DEBUG_MSG("is charging %d\n", axp.isChargeing());
return 30 * 1000;
}
Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup();
#endif

View File

@@ -1,44 +0,0 @@
#include "../configuration.h"
#include "../main.h"
#include <Wire.h>
#ifndef NO_WIRE
void scanI2Cdevice(void)
{
byte err, addr;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
nDevices++;
if (addr == SSD1306_ADDRESS) {
screen_found = addr;
DEBUG_MSG("ssd1306 display found\n");
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
DEBUG_MSG("st7567 display found\n");
}
#ifdef AXP192_SLAVE_ADDRESS
if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true;
DEBUG_MSG("axp192 PMU found\n");
}
#endif
} else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
DEBUG_MSG("No I2C devices found\n");
else
DEBUG_MSG("done\n");
}
#else
void scanI2Cdevice(void) {}
#endif

View File

@@ -104,8 +104,8 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble
} else {
if (Update.end()) {
if (update_region == U_SPIFFS) {
DEBUG_MSG("Filesystem updated!\n");
nodeDB.saveToDisk(); // Since we just wiped the filesystem, we need to save our current state
DEBUG_MSG("SPIFFS updated!\n");
nodeDB.saveToDisk(); // Since we just wiped spiffs, we need to save our current state
} else {
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
rebootAtMsec = millis() + 5000;

View File

@@ -1,84 +0,0 @@
#include "configuration.h"
#include "Air530GPS.h"
#include <assert.h>
/*
Helpful translations from the Air530 GPS datasheet
Sat acquision mode
捕获电流值@3.3v 42.6 mA
sat tracking mode
跟踪电流值@3.3v 36.7 mA
Low power mode
低功耗模式@3.3V 0.85 mA
(发送指令:$PGKC051,0)
Super low power mode
超低功耗模式@3.3V 31 uA
(发送指令:$PGKC105,4)
To exit sleep use WAKE pin
Commands to enter sleep
6、Command: 105
进入周期性低功耗模式
Arguments:
Arg1: “0”,正常运行模式 (normal mode)
“1”,周期超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (periodic low power tracking mode - keeps sat positions, use wake to wake up)
“2”,周期低功耗模式 (periodic low power mode)
“4”,直接进入超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (super low power consumption mode immediately, need WAKE to resume)
“8”,自动低功耗模式,可以通过串口唤醒 (automatic low power mode, wake by sending characters to serial port)
“9”, 自动超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (automatic low power tracking when possible, need wake pin to resume)
(Arg 2 & 3 only valid if Arg1 is "1" or "2")
Arg2:运行时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用
ON time in msecs
Arg3:睡眠时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用
Sleep time in msecs
Example:
$PGKC105,8*3F<CR><LF>
This will set automatic low power mode with waking when we send chars to the serial port. Possibly do this as soon as we get a
new location. When we wake again in a minute we send a character to wake up.
*/
void Air530GPS::sendCommand(const char *cmd) {
uint8_t sum = 0;
// Skip the $
assert(cmd[0] == '$');
const char *p = cmd + 1;
while(*p)
sum ^= *p++;
assert(_serial_gps);
_serial_gps->write(cmd);
_serial_gps->printf("*%02x\r\n", sum);
// DEBUG_MSG("xsum %02x\n", sum);
}
void Air530GPS::sleep() {
NMEAGPS::sleep();
#ifdef PIN_GPS_WAKE
sendCommand("$PGKC105,4");
#endif
}
/// wake the GPS into normal operation mode
void Air530GPS::wake()
{
#if 1
NMEAGPS::wake();
#else
// For power testing - keep GPS sleeping forever
sleep();
#endif
}

View File

@@ -1,22 +0,0 @@
#pragma once
#include "NMEAGPS.h"
/**
* A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class Air530GPS : public NMEAGPS
{
protected:
/// If possible force the GPS into sleep/low power mode
virtual void sleep() override;
/// wake the GPS into normal operation mode
virtual void wake() override;
private:
/// Send a NMEA cmd with checksum
void sendCommand(const char *str);
};

View File

@@ -16,18 +16,49 @@ HardwareSerial *GPS::_serial_gps = &Serial1;
HardwareSerial *GPS::_serial_gps = NULL;
#endif
#ifdef GPS_I2C_ADDRESS
uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
#else
uint8_t GPS::i2cAddress = 0;
#endif
GPS *gps;
/// Multiple GPS instances might use the same serial port (in sequence), but we can
/// only init that port once.
static bool didSerialInit;
bool GPS::getACK(uint8_t c, uint8_t i) {
uint8_t b;
uint8_t ack = 0;
const uint8_t ackP[2] = {c, i};
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned long startTime = millis();
for (int j = 2; j < 6; j++) {
buf[8] += buf[j];
buf[9] += buf[8];
}
for (int j = 0; j < 2; j++) {
buf[6 + j] = ackP[j];
buf[8] += buf[6 + j];
buf[9] += buf[8];
}
while (1) {
if (ack > 9) {
return true;
}
if (millis() - startTime > 1000) {
return false;
}
if (_serial_gps->available()) {
b = _serial_gps->read();
if (b == buf[ack]) {
ack++;
}
else {
ack = 0;
}
}
}
}
bool GPS::setupGPS()
{
if (_serial_gps && !didSerialInit) {
@@ -41,6 +72,96 @@ bool GPS::setupGPS()
#endif
#ifndef NO_ESP32
_serial_gps->setRxBufferSize(2048); // the default is 256
#endif
#ifdef TTGO_T_ECHO
// Switch to 9600 baud, then close and reopen port
_serial_gps->end();
delay(250);
_serial_gps->begin(4800);
delay(250);
_serial_gps->write("$PCAS01,1*1D\r\n");
delay(250);
_serial_gps->end();
delay(250);
_serial_gps->begin(9600);
delay(250);
// Initialize the L76K Chip, use GPS + GLONASS
_serial_gps->write("$PCAS04,5*1C\r\n");
delay(250);
// only ask for RMC and GGA
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
delay(250);
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n");
delay(250);
#endif
#ifdef GPS_UBLOX
delay(250);
// Set the UART port to output NMEA only
byte _message_nmea[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00,
0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x91, 0xAF};
_serial_gps->write(_message_nmea,sizeof(_message_nmea));
if (!getACK(0x06, 0x00)) {
DEBUG_MSG("WARNING: Unable to enable NMEA Mode.\n");
return true;
}
// disable GGL
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x05,0x3A};
_serial_gps->write(_message_GGL,sizeof(_message_GGL));
if (!getACK(0x06, 0x01)) {
DEBUG_MSG("WARNING: Unable to disable NMEA GGL.\n");
return true;
}
// disable GSA
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x06,0x41};
_serial_gps->write(_message_GSA,sizeof(_message_GSA));
if (!getACK(0x06, 0x01)) {
DEBUG_MSG("WARNING: Unable to disable NMEA GSA.\n");
return true;
}
// disable GSV
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x07,0x48};
_serial_gps->write(_message_GSV,sizeof(_message_GSV));
if (!getACK(0x06, 0x01)) {
DEBUG_MSG("WARNING: Unable to disable NMEA GSV.\n");
return true;
}
// disable VTG
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x09,0x56};
_serial_gps->write(_message_VTG,sizeof(_message_VTG));
if (!getACK(0x06, 0x01)) {
DEBUG_MSG("WARNING: Unable to disable NMEA VTG.\n");
return true;
}
// enable RMC
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x09,0x54};
_serial_gps->write(_message_RMC,sizeof(_message_RMC));
if (!getACK(0x06, 0x01)) {
DEBUG_MSG("WARNING: Unable to enable NMEA RMC.\n");
return true;
}
// enable GGA
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x05, 0x38};
_serial_gps->write(_message_GGA,sizeof(_message_GGA));
if (!getACK(0x06, 0x01)) DEBUG_MSG("WARNING: Unable to enable NMEA GGA.\n");
#endif
}
@@ -51,7 +172,7 @@ bool GPS::setup()
{
// Master power for the GPS
#ifdef PIN_GPS_EN
digitalWrite(PIN_GPS_EN, PIN_GPS_EN);
digitalWrite(PIN_GPS_EN, 1);
pinMode(PIN_GPS_EN, OUTPUT);
#endif
@@ -82,6 +203,11 @@ GPS::~GPS()
bool GPS::hasLock() { return hasValidLocation; }
bool GPS::hasFlow()
{
return hasGPS;
}
// Allow defining the polarity of the WAKE output. default is active high
#ifndef GPS_WAKE_ACTIVE
#define GPS_WAKE_ACTIVE 1
@@ -218,6 +344,15 @@ int32_t GPS::runOnce()
if (whileIdle()) {
// if we have received valid NMEA claim we are connected
setConnected();
} else {
#ifdef GPS_UBLOX
// reset the GPS on next bootup
if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) {
DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n");
devicestate.did_gps_reset = false;
nodeDB.saveToDisk();
}
#endif
}
// If we are overdue for an update, turn on the GPS and at least publish the current status
@@ -257,7 +392,6 @@ int32_t GPS::runOnce()
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
// Once we get a location we no longer desperately want an update
// or if we got a time and we are in GpsOpTimeOnly mode
// DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
if ((gotLoc && gotTime) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) {
@@ -280,7 +414,7 @@ int32_t GPS::runOnce()
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
return isAwake ? 100 : 5000;
return isAwake ? GPS_THREAD_INTERVAL : 5000;
}
void GPS::forceWake(bool on)
@@ -318,13 +452,7 @@ int GPS::prepareDeepSleep(void *unused)
return 0;
}
#ifdef GPS_TX_PIN
#include "UBloxGPS.h"
#endif
#ifdef HAS_AIR530_GPS
#include "Air530GPS.h"
#elif !defined(NO_GPS)
#ifndef NO_GPS
#include "NMEAGPS.h"
#endif
@@ -339,29 +467,11 @@ GPS *createGps()
#else
DEBUG_MSG("Using MSL altitude model\n");
#endif
// If we don't have bidirectional comms, we can't even try talking to UBLOX
#ifdef GPS_TX_PIN
// Init GPS - first try ublox
UBloxGPS *ublox = new UBloxGPS();
if (!ublox->setup()) {
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
delete ublox;
ublox = NULL;
} else {
return ublox;
}
#endif
if (GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NMEA at 9600 baud.
DEBUG_MSG("Hoping that NMEA might work\n");
#ifdef HAS_AIR530_GPS
GPS *new_gps = new Air530GPS();
#else
GPS *new_gps = new NMEAGPS();
#endif
new_gps->setup();
return new_gps;
}

View File

@@ -40,9 +40,6 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
/** If !0 we will attempt to connect to the GPS over I2C */
static uint8_t i2cAddress;
Position p = Position_init_default;
GPS() : concurrency::OSThread("GPS") {}
@@ -60,6 +57,9 @@ class GPS : private concurrency::OSThread
/// Returns true if we have acquired GPS lock.
virtual bool hasLock();
/// Returns true if there's valid data flow with the chip.
virtual bool hasFlow();
/// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; }
@@ -140,6 +140,8 @@ class GPS : private concurrency::OSThread
GpsOperation getGpsOp() const;
bool getACK(uint8_t c, uint8_t i);
/**
* Tell users we have new GPS readings
*/

View File

@@ -5,7 +5,7 @@
#include <TinyGPS++.h>
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
#define GPS_SOL_EXPIRY_MS 300 // in millis
#define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
static int32_t toDegInt(RawDegrees d)
@@ -17,6 +17,19 @@ static int32_t toDegInt(RawDegrees d)
return r;
}
bool NMEAGPS::factoryReset()
{
#ifdef GPS_UBLOX
// Factory Reset
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF,
0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
_serial_gps->write(_message_reset,sizeof(_message_reset));
delay(1000);
#endif
return true;
}
bool NMEAGPS::setupGPS()
{
GPS::setupGPS();
@@ -64,11 +77,12 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
DEBUG_MSG("NMEA GPS time %d\n", t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
if (t.tm_mon > -1){
DEBUG_MSG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
} else
return false;
} else
return false;
}
@@ -116,7 +130,7 @@ bool NMEAGPS::lookForLocation()
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
{
DEBUG_MSG("SOME data is TOO OLD\n");
DEBUG_MSG("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age());
return false;
}
@@ -127,10 +141,17 @@ bool NMEAGPS::lookForLocation()
// We know the solution is fresh and valid, so just read the data
auto loc = reader.location.value();
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
// Bail out EARLY to avoid overwriting previous good data (like #857)
if(toDegInt(loc.lat) == 0) {
DEBUG_MSG("Ignoring bogus NMEA position\n");
if (toDegInt(loc.lat) > 900000000) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat));
#endif
return false;
}
if (toDegInt(loc.lng) > 1800000000) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng));
#endif
return false;
}
@@ -214,6 +235,10 @@ bool NMEAGPS::hasLock()
return false;
}
bool NMEAGPS::hasFlow()
{
return reader.passedChecksum() > 0;
}
bool NMEAGPS::whileIdle()
{

View File

@@ -25,6 +25,8 @@ class NMEAGPS : public GPS
public:
virtual bool setupGPS() override;
virtual bool factoryReset() override;
protected:
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
@@ -49,4 +51,6 @@ class NMEAGPS : public GPS
virtual bool lookForLocation() override;
virtual bool hasLock() override;
virtual bool hasFlow() override;
};

View File

@@ -1,328 +0,0 @@
#include "configuration.h"
#include "UBloxGPS.h"
#include "RTC.h"
#include "error.h"
#include "sleep.h"
#include <assert.h>
// if gps_update_interval below this value, do not powercycle the GPS
#define UBLOX_POWEROFF_THRESHOLD 90
#define PDOP_INVALID 9999
// #define UBX_MODE_NMEA
extern RadioConfig radioConfig;
UBloxGPS::UBloxGPS() {}
bool UBloxGPS::tryConnect()
{
bool c = false;
if (_serial_gps)
c = ublox.begin(*_serial_gps);
if (!c && i2cAddress) {
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
// supports the newer API
neo6M = true;
c = ublox.begin(Wire, i2cAddress);
}
if (c)
setConnected();
return c;
}
bool UBloxGPS::setupGPS()
{
GPS::setupGPS();
// uncomment to see debug info
// ublox.enableDebugging(Serial);
// try a second time, the ublox lib serial parsing is buggy?
// see https://github.com/meshtastic/Meshtastic-device/issues/376
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
if (isConnected()) {
#ifdef UBX_MODE_NMEA
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
#else
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
#endif
if (!setUBXMode())
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
#ifdef UBX_MODE_NMEA
return false;
#else
return true;
#endif
} else {
return false;
}
}
bool UBloxGPS::setUBXMode()
{
#ifdef UBX_MODE_NMEA
if (_serial_gps) {
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
}
if (i2cAddress) {
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
}
return false; // pretend initialization failed to force NMEA mode
#endif
if (_serial_gps) {
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
return false;
}
if (i2cAddress) {
if (!ublox.setI2COutput(COM_TYPE_UBX, 1000))
return false;
}
if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low
return false;
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
// assert(ok);
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
// assert(ok);
// per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal
// TTGO antennas
// if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight)
// return false;
if (!ublox.saveConfiguration(3000))
return false;
return true;
}
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool UBloxGPS::factoryReset()
{
bool ok = false;
// It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have
// GPS_TX connected)
ublox.factoryReset();
delay(5000);
tryConnect(); // sets isConnected
// try a second time, the ublox lib serial parsing is buggy?
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
DEBUG_MSG("GPS Factory reset success=%d\n", isConnected());
if (isConnected())
ok = setUBXMode();
return ok;
}
/** Idle processing while GPS is looking for lock */
void UBloxGPS::whileActive()
{
ublox.flushPVT(); // reset ALL freshness flags first
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
// Ask for a new position fix - hopefully it will have results ready by next time
// the order here is important, because we only check for has latitude when reading
//ublox.getSIV(maxWait()); // redundant with getPDOP below
ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others
ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others
// the fixType flag will be checked and updated in lookForLocation()
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForTime()
{
if (ublox.moduleQueried.gpsSecond) {
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January
1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
t.tm_hour = ublox.getHour(0);
t.tm_mday = ublox.getDay(0);
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
perhapsSetRTC(RTCQualityGPS, t);
return true;
}
return false;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForLocation()
{
bool foundLocation = false;
// check if a complete GPS solution set is available for reading
// (some of these, like lat/lon are redundant and can be removed)
if ( ! (ublox.moduleQueried.fixType &&
ublox.moduleQueried.latitude &&
ublox.moduleQueried.longitude &&
ublox.moduleQueried.altitude &&
ublox.moduleQueried.pDOP &&
ublox.moduleQueried.SIV &&
ublox.moduleQueried.gpsDay))
{
// Not ready? No problem! We'll try again later.
return false;
}
fixType = ublox.getFixType();
#ifdef UBLOX_EXTRAVERBOSE
DEBUG_MSG("FixType=%d\n", fixType);
#endif
// check if GPS has an acceptable lock
if (! hasLock()) {
ublox.flushPVT(); // reset ALL freshness flags
return false;
}
// read lat/lon/alt/dop data into temporary variables to avoid
// overwriting global variables with potentially invalid data
int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
int32_t tmp_lat = ublox.getLatitude(0);
int32_t tmp_lon = ublox.getLongitude(0);
int32_t tmp_alt_msl = ublox.getAltitudeMSL(0);
int32_t tmp_alt_hae = ublox.getAltitude(0);
int32_t max_dop = PDOP_INVALID;
if (radioConfig.preferences.gps_max_dop)
max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
// don't read it here - it will generate an ignored getPVT command on the 6ms
// heading = ublox.getHeading(0);
// read positional timestamp
struct tm t;
t.tm_sec = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
t.tm_hour = ublox.getHour(0);
t.tm_mday = ublox.getDay(0);
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
time_t tmp_ts = mktime(&t);
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
// FIXME - NULL ISLAND is a real location on Earth!
foundLocation = (tmp_lat != 0) && (tmp_lon != 0) &&
(tmp_lat <= 900000000) && (tmp_lat >= -900000000) &&
(tmp_dop < max_dop);
// only if entire dataset is valid, update globals from temp vars
if (foundLocation) {
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
p.longitude_i = tmp_lon;
p.latitude_i = tmp_lat;
if (fixType > 2) {
// if fix is 2d, ignore altitude data
p.altitude = tmp_alt_msl / 1000;
p.altitude_hae = tmp_alt_hae / 1000;
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
} else {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("no altitude data (fixType=%d)\n", fixType);
#endif
// clean up old values in case it's a 3d-2d fix transition
p.altitude = p.altitude_hae = p.alt_geoid_sep = 0;
}
p.pos_timestamp = tmp_ts;
p.PDOP = tmp_dop;
p.fix_type = fixType;
p.sats_in_view = ublox.getSIV(0);
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
} else {
// INVALID solution - should never happen
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop);
}
ublox.flushPVT(); // reset ALL freshness flags at the end
return foundLocation;
}
bool UBloxGPS::hasLock()
{
if (radioConfig.preferences.gps_accept_2d)
return (fixType >= 2 && fixType <= 4);
else
return (fixType >= 3 && fixType <= 4);
}
bool UBloxGPS::whileIdle()
{
// if using i2c or serial look too see if any chars are ready
return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
}
/// If possible force the GPS into sleep/low power mode
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
void UBloxGPS::sleep()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
ublox.powerOff();
// setGPSPower(false);
}
}
void UBloxGPS::wake()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
fixType = 0; // assume we have no fix yet
}
// this is idempotent
setGPSPower(true);
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
// Give time for the GPS to boot
// delay(200);
}

View File

@@ -1,72 +0,0 @@
#pragma once
#include "GPS.h"
#include "Observer.h"
#include "SparkFun_Ublox_Arduino_Library.h"
/**
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class UBloxGPS : public GPS
{
SFE_UBLOX_GPS ublox;
uint8_t fixType = 0;
public:
UBloxGPS();
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool factoryReset() override;
protected:
/**
* Returns true if we succeeded
*/
virtual bool setupGPS() override;
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() override;
/** Idle processing while GPS is looking for lock */
virtual void whileActive() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() override;
virtual bool hasLock() override;
/// If possible force the GPS into sleep/low power mode
virtual void sleep() override;
virtual void wake() override;
private:
/// Attempt to connect to our GPS, returns false if no gps is present
bool tryConnect();
/// Switch to our desired operating mode and save the settings to flash
/// returns true for success
bool setUBXMode();
uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
};

View File

@@ -9,45 +9,14 @@
#define COLORED GxEPD_BLACK
#define UNCOLORED GxEPD_WHITE
#if defined(TTGO_T_ECHO)
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67
#elif defined(RAK4630)
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
#define TECHO_DISPLAY_MODEL GxEPD2_213_B74
//4.2 inch 300x400 - GxEPD2_420_M01
//#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
//2.9 inch 296x128 - GxEPD2_290_T5D
//#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
//1.54 inch 200x200 - GxEPD2_154_M09
//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
#endif
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
{
#if defined(TTGO_T_ECHO)
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
#elif defined(RAK4630)
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
setGeometry(GEOMETRY_RAWMODE, 250, 122);
//GxEPD2_420_M01
//setGeometry(GEOMETRY_RAWMODE, 300, 400);
//GxEPD2_290_T5D
//setGeometry(GEOMETRY_RAWMODE, 296, 128);
//GxEPD2_154_M09
//setGeometry(GEOMETRY_RAWMODE, 200, 200);
#endif
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
}
@@ -71,8 +40,8 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint64_t y = 0; y < displayHeight; y++) {
for (uint64_t x = 0; x < displayWidth; x++) {
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];
@@ -81,28 +50,9 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
}
}
#if defined(TTGO_T_ECHO)
DEBUG_MSG("Updating T-ECHO E-Paper... ");
#elif defined(RAK4630)
DEBUG_MSG("Updating RAK4361_5005 E-Paper... ");
#endif
#if defined(TTGO_T_ECHO)
DEBUG_MSG("Updating eink... ");
// ePaper.Reset(); // wake the screen from sleep
adafruitDisplay->display(false); // FIXME, use partial update mode
#elif defined(RAK4630)
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
adafruitDisplay->display(false); // FIXME, use partial update mode
//Only enable for e-Paper with support for partial updates and comment out above adafruitDisplay->display(false);
// 1.54 inch 200x200 - GxEPD2_154_M09
// 2.9 inch 296x128 - GxEPD2_290_T5D
// 4.2 inch 300x400 - GxEPD2_420_M01
//adafruitDisplay->nextPage();
#endif
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
adafruitDisplay->hibernate();
DEBUG_MSG("done\n");
@@ -147,33 +97,14 @@ bool EInkDisplay::connect()
pinMode(PIN_EINK_EN, OUTPUT);
#endif
#if defined(TTGO_T_ECHO)
{
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS,
PIN_EINK_DC,
PIN_EINK_RES,
PIN_EINK_BUSY, SPI1);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init();
adafruitDisplay->setRotation(3);
}
#elif defined(RAK4630)
{
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
adafruitDisplay->setRotation(3);
//For 1.54, 2.9 and 4.2
//adafruitDisplay->setRotation(1);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
}
#endif
//adafruitDisplay->setFullWindow();
//adafruitDisplay->fillScreen(UNCOLORED);
//adafruitDisplay->drawCircle(100, 100, 20, COLORED);

View File

@@ -32,7 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "main.h"
#include "mesh-pb-constants.h"
#include "mesh/Channels.h"
#include "modules/TextMessageModule.h"
#include "plugins/TextMessagePlugin.h"
#include "sleep.h"
#include "target_specific.h"
#include "utils.h"
@@ -67,9 +67,9 @@ uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
// Threshold values for the GPS lock accuracy bar display
uint32_t dopThresholds[5] = {2000, 1000, 500, 200, 100};
// At some point, we're going to ask all of the modules if they would like to display a screen frame
// we'll need to hold onto pointers for the modules that can draw a frame.
std::vector<MeshPlugin *> moduleFrames;
// At some point, we're going to ask all of the plugins if they would like to display a screen frame
// we'll need to hold onto pointers for the plugins that can draw a frame.
std::vector<MeshPlugin *> pluginFrames;
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
static char ourId[5];
@@ -176,9 +176,9 @@ static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int
}
#endif
static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
uint8_t module_frame;
uint8_t plugin_frame;
// there's a little but in the UI transition code
// where it invokes the function at the correct offset
// in the array of "drawScreen" functions; however,
@@ -187,14 +187,14 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) {
// if we're transitioning from the end of the frame list back around to the first
// frame, then we want this to be `0`
module_frame = state->transitionFrameTarget;
plugin_frame = state->transitionFrameTarget;
} else {
// otherwise, just display the module frame that's aligned with the current frame
module_frame = state->currentFrame;
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", module_frame);
// otherwise, just display the plugin frame that's aligned with the current frame
plugin_frame = state->currentFrame;
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
}
// DEBUG_MSG("Drawing Module Frame %d\n\n", module_frame);
MeshPlugin &pi = *moduleFrames.at(module_frame);
// DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
pi.drawFrame(display, state, x, y);
}
@@ -259,11 +259,11 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
}
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward plugin are enabled
static bool shouldDrawMessage(const MeshPacket *packet)
{
return packet->from != 0 && !radioConfig.preferences.range_test_module_enabled &&
!radioConfig.preferences.store_forward_module_enabled;
return packet->from != 0 && !radioConfig.preferences.range_test_plugin_enabled &&
!radioConfig.preferences.store_forward_plugin_enabled;
}
/// Draw the last text message we received
@@ -824,10 +824,10 @@ void Screen::setup()
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
if (textMessageModule)
textMessageObserver.observe(textMessageModule);
if (textMessagePlugin)
textMessageObserver.observe(textMessagePlugin);
// Modules can notify screen about refresh
// Plugins can notify screen about refresh
MeshPlugin::observeUIEvents(&uiFrameEventObserver);
}
@@ -976,9 +976,9 @@ void Screen::setFrames()
DEBUG_MSG("showing standard frames\n");
showingNormalScreen = true;
moduleFrames = MeshPlugin::GetMeshModulesWithUIFrames();
DEBUG_MSG("Showing %d module frames\n", moduleFrames.size());
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
pluginFrames = MeshPlugin::GetMeshPluginsWithUIFrames();
DEBUG_MSG("Showing %d plugin frames\n", pluginFrames.size());
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + pluginFrames.size();
DEBUG_MSG("Total frame count: %d\n", totalFrameCount);
// We don't show the node info our our node (if we have it yet - we should)
@@ -988,23 +988,23 @@ void Screen::setFrames()
size_t numframes = 0;
// put all of the module frames first.
// put all of the plugin frames first.
// this is a little bit of a dirty hack; since we're going to call
// the same drawModuleFrame handler here for all of these module frames
// the same drawPluginFrame handler here for all of these plugin frames
// and then we'll just assume that the state->currentFrame value
// is the same offset into the moduleFrames vector
// so that we can invoke the module's callback
for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) {
normalFrames[numframes++] = drawModuleFrame;
// is the same offset into the pluginFrames vector
// so that we can invoke the plugin's callback
for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) {
normalFrames[numframes++] = drawPluginFrame;
}
DEBUG_MSG("Added modules. numframes: %d\n", numframes);
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
// If we have a critical fault, show it first
if (myNodeInfo.error_code)
normalFrames[numframes++] = drawCriticalFaultFrame;
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
// If we have a text message - show it next, unless it's a phone message and we aren't using any special plugins
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
normalFrames[numframes++] = drawTextMessageFrame;
}

View File

@@ -1,4 +1,5 @@
#include "InputBroker.h"
#include "PowerFSM.h" // needed for event trigger
InputBroker *inputBroker;
@@ -13,6 +14,7 @@ void InputBroker::registerSource(Observable<const InputEvent *> *source)
int InputBroker::handleInputEvent(const InputEvent *event)
{
powerFSM.trigger(EVENT_INPUT);
this->notifyObservers(event);
return 0;
}

View File

@@ -54,7 +54,7 @@ int32_t RotaryEncoderInterruptBase::runOnce()
}
else if (this->action == ROTARY_ACTION_CCW)
{
DEBUG_MSG("Rotary event CW\n");
DEBUG_MSG("Rotary event CCW\n");
e.inputEvent = this->_eventCcw;
}
@@ -84,7 +84,7 @@ void RotaryEncoderInterruptBase::intAHandler()
return;
}
this->rotaryLevelA = currentLevelA;
intHandler(
this->rotaryStateCCW = intHandler(
currentLevelA == HIGH,
this->rotaryLevelB,
ROTARY_ACTION_CCW,

View File

@@ -27,7 +27,7 @@ void RotaryEncoderInterruptImpl1::init()
char eventPressed =
static_cast<char>(radioConfig.preferences.rotary1_event_press);
//radioConfig.preferences.ext_notification_module_output
//radioConfig.preferences.ext_notification_plugin_output
RotaryEncoderInterruptBase::init(
pinA, pinB, pinPress,
eventCw, eventCcw, eventPressed,

View File

@@ -18,12 +18,10 @@
#include "concurrency/Periodic.h"
#include "graphics/Screen.h"
#include "main.h"
#include "modules/Modules.h"
#include "plugins/Plugins.h"
#include "sleep.h"
#include "shutdown.h"
#include "target_specific.h"
#include "debug/i2cScan.h"
#include "debug/axpDebug.h"
#include <OneButton.h>
#include <Wire.h>
// #include <driver/rtc_io.h>
@@ -44,8 +42,6 @@
#include "SX1268Interface.h"
#include "LLCC68Interface.h"
#include "ButtonThread.h"
#include "PowerFSMThread.h"
using namespace concurrency;
@@ -68,6 +64,50 @@ bool axp192_found;
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
// -----------------------------------------------------------------------------
// Application
// -----------------------------------------------------------------------------
#ifndef NO_WIRE
void scanI2Cdevice(void)
{
byte err, addr;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
nDevices++;
if (addr == SSD1306_ADDRESS) {
screen_found = addr;
DEBUG_MSG("ssd1306 display found\n");
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
DEBUG_MSG("st7567 display found\n");
}
#ifdef AXP192_SLAVE_ADDRESS
if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true;
DEBUG_MSG("axp192 PMU found\n");
}
#endif
} else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
DEBUG_MSG("No I2C devices found\n");
else
DEBUG_MSG("done\n");
}
#else
void scanI2Cdevice(void) {}
#endif
const char *getDeviceName()
{
uint8_t dmac[6];
@@ -93,6 +133,238 @@ static int32_t ledBlinker()
uint32_t timeLastPowered = 0;
/// Wrapper to convert our powerFSM stuff into a 'thread'
class PowerFSMThread : public OSThread
{
public:
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
PowerFSMThread() : OSThread("PowerFSM") {}
protected:
int32_t runOnce() override
{
powerFSM.run_machine();
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
/// cpu for serial rx - FIXME)
auto state = powerFSM.getState();
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
if (powerStatus->getHasUSB()) {
timeLastPowered = millis();
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 &&
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered
powerFSM.trigger(EVENT_SHUTDOWN);
}
return 10;
}
};
/**
* Watch a GPIO and if we get an IRQ, wake the main thread.
* Use to add wake on button press
*/
void wakeOnIrq(int irq, int mode)
{
attachInterrupt(
irq,
[] {
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
},
FALLING);
}
class ButtonThread : public OSThread
{
// Prepare for button presses
#ifdef BUTTON_PIN
OneButton userButton;
#endif
#ifdef BUTTON_PIN_ALT
OneButton userButtonAlt;
#endif
#ifdef BUTTON_PIN_TOUCH
OneButton userButtonTouch;
#endif
static bool shutdown_on_long_stop;
public:
static uint32_t longPressTime;
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
#endif
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed);
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
#endif
userButtonAlt.attachClick(userButtonPressed);
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
#ifdef BUTTON_PIN_TOUCH
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
userButtonTouch.attachClick(touchPressed);
userButtonTouch.attachDuringLongPress(touchPressedLong);
userButtonTouch.attachDoubleClick(touchDoublePressed);
userButtonTouch.attachLongPressStart(touchPressedLongStart);
userButtonTouch.attachLongPressStop(touchPressedLongStop);
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
#endif
}
protected:
/// If the button is pressed we suppress CPU sleep until release
int32_t runOnce() override
{
canSleep = true; // Assume we should not keep the board awake
#ifdef BUTTON_PIN
userButton.tick();
canSleep &= userButton.isIdle();
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
canSleep &= userButtonAlt.isIdle();
#endif
#ifdef BUTTON_PIN_TOUCH
userButtonTouch.tick();
canSleep &= userButtonTouch.isIdle();
#endif
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
// else DEBUG_MSG("sleep ok\n");
return 5;
}
private:
static void touchPressed()
{
screen->forceDisplay();
DEBUG_MSG("touch press!\n");
}
static void touchDoublePressed()
{
DEBUG_MSG("touch double press!\n");
}
static void touchPressedLong()
{
DEBUG_MSG("touch press long!\n");
}
static void touchDoublePressedLong()
{
DEBUG_MSG("touch double pressed!\n");
}
static void touchPressedLongStart()
{
DEBUG_MSG("touch long press start!\n");
}
static void touchPressedLongStop()
{
DEBUG_MSG("touch long press stop!\n");
}
static void userButtonPressed()
{
// DEBUG_MSG("press!\n");
#ifdef BUTTON_PIN
if ((BUTTON_PIN != radioConfig.preferences.rotary1_pin_press) || !radioConfig.preferences.canned_message_plugin_enabled) {
powerFSM.trigger(EVENT_PRESS);
}
#endif
}
static void userButtonPressedLong()
{
// DEBUG_MSG("Long press!\n");
#ifndef NRF52_SERIES
screen->adjustBrightness();
#endif
// If user button is held down for 5 seconds, shutdown the device.
if (millis() - longPressTime > 5 * 1000) {
#ifdef TBEAM_V10
if (axp192_found == true) {
setLed(false);
power->shutdown();
}
#elif NRF52_SERIES
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
if (!shutdown_on_long_stop) {
screen->startShutdownScreen();
DEBUG_MSG("Shutdown from long press");
playBeep();
ledOff(PIN_LED1);
ledOff(PIN_LED2);
shutdown_on_long_stop = true;
}
#endif
} else {
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
}
}
static void userButtonDoublePressed()
{
#ifndef NO_ESP32
disablePin();
#elif defined(HAS_EINK)
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW);
#endif
}
static void userButtonMultiPressed()
{
#ifndef NO_ESP32
clearNVS();
#endif
#ifdef NRF52_SERIES
clearBonds();
#endif
}
static void userButtonPressedLongStart()
{
DEBUG_MSG("Long press start!\n");
longPressTime = millis();
}
static void userButtonPressedLongStop()
{
DEBUG_MSG("Long press stop!\n");
longPressTime = 0;
if (shutdown_on_long_stop) {
playShutdownMelody();
delay(3000);
power->shutdown();
}
}
};
bool ButtonThread::shutdown_on_long_stop = false;
static Periodic *ledPeriodic;
@@ -132,6 +404,12 @@ void setup()
initDeepSleep();
// Testing this fix für erratic T-Echo boot behaviour
#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON)
pinMode(PIN_EINK_PWR_ON, OUTPUT);
digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif
#ifdef VEXT_ENABLE
pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
@@ -238,6 +516,22 @@ void setup()
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
#ifdef GENIEBLOCKS
Im intentionally breaking your build so you see this note.Feel free to revert if not correct.I think you can
remove this GPS_RESET_N code by instead defining PIN_GPS_RESET and
use the shared code in GPS.cpp instead.- geeksville
// gps setup
pinMode(GPS_RESET_N, OUTPUT);
pinMode(GPS_EXTINT, OUTPUT);
digitalWrite(GPS_RESET_N, HIGH);
digitalWrite(GPS_EXTINT, LOW);
// battery setup
// If we want to read battery level, we need to set BATTERY_EN_PIN pin to low.
// ToDo: For low power consumption after read battery level, set that pin to high.
pinMode(BATTERY_EN_PIN, OUTPUT);
digitalWrite(BATTERY_EN_PIN, LOW);
#endif
gps = createGps();
if (gps)
@@ -249,8 +543,8 @@ void setup()
service.init();
// Now that the mesh service is created, create any modules
setupModules();
// Now that the mesh service is created, create any plugins
setupPlugins();
// Do this after service.init (because that clears error_code)
#ifdef AXP192_SLAVE_ADDRESS
@@ -273,6 +567,7 @@ void setup()
// ONCE we will factory reset the GPS for bug #327
if (gps && !devicestate.did_gps_reset) {
DEBUG_MSG("GPS FactoryReset requested\n");
if (gps->factoryReset()) { // If we don't succeed try again next time
devicestate.did_gps_reset = true;
nodeDB.saveToDisk();
@@ -392,9 +687,68 @@ void setup()
setCPUFast(false); // 80MHz is fine for our slow peripherals
}
#if 0
// Turn off for now
uint32_t axpDebugRead()
{
axp.debugCharging();
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
DEBUG_MSG("is charging %d\n", axp.isChargeing());
return 30 * 1000;
}
Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup();
#endif
uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client)
void powerCommandsCheck()
{
if (rebootAtMsec && millis() > rebootAtMsec) {
#ifndef NO_ESP32
DEBUG_MSG("Rebooting for update\n");
ESP.restart();
#elif NRF52_SERIES
NVIC_SystemReset();
#else
DEBUG_MSG("FIXME implement reboot for this platform");
#endif
}
#if NRF52_SERIES
if (shutdownAtMsec) {
screen->startShutdownScreen();
playBeep();
ledOff(PIN_LED1);
ledOff(PIN_LED2);
}
#endif
if (shutdownAtMsec && millis() > shutdownAtMsec) {
DEBUG_MSG("Shutting down from admin command\n");
#ifdef TBEAM_V10
if (axp192_found == true) {
setLed(false);
power->shutdown();
}
#elif NRF52_SERIES
playShutdownMelody();
power->shutdown();
#else
DEBUG_MSG("FIXME implement shutdown for this platform");
#endif
}
}
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
// This will supress the current delay and instead try to run ASAP.
bool runASAP;

View File

@@ -5,7 +5,6 @@
#include "PowerStatus.h"
#include "graphics/Screen.h"
extern uint8_t screen_found;
extern bool axp192_found;
extern bool isCharging;
extern bool isUSBPowered;
@@ -21,8 +20,6 @@ extern graphics::Screen *screen;
// Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName();
extern uint32_t timeLastPowered;
extern uint32_t rebootAtMsec;
extern uint32_t shutdownAtMsec;

View File

@@ -7,7 +7,7 @@
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01};
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
Channels channels;
@@ -84,7 +84,10 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
Channel &ch = getByIndex(chIndex);
ChannelSettings &channelSettings = ch.settings;
channelSettings.modem_config = ChannelSettings_ModemConfig_LongFast; // Default to Long Range & Fast
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
// channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide
// bandwidth so incompatible radios can talk together
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
channelSettings.tx_power = 0; // default
uint8_t defaultpskIndex = 1;
@@ -213,26 +216,23 @@ const char *Channels::getName(size_t chIndex)
channelName = "Unset";
else
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_ShortSlow:
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
channelName = "ShortSlow";
break;
case ChannelSettings_ModemConfig_ShortFast:
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
channelName = "ShortFast";
break;
case ChannelSettings_ModemConfig_MidSlow:
channelName = "MediumSlow";
break;
case ChannelSettings_ModemConfig_MidFast:
channelName = "MediumFast";
break;
case ChannelSettings_ModemConfig_LongFast:
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
channelName = "LongFast";
break;
case ChannelSettings_ModemConfig_LongSlow:
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
channelName = "LongSlow";
break;
case ChannelSettings_ModemConfig_VLongSlow:
channelName = "VLongSlow";
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
channelName = "MediumSlow";
break;
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
channelName = "MediumFast";
break;
default:
channelName = "Invalid";

View File

@@ -1,5 +1,5 @@
#include "FloodingRouter.h"
#include "configuration.h"
#include "FloodingRouter.h"
#include "mesh-pb-constants.h"
FloodingRouter::FloodingRouter() {}
@@ -27,41 +27,11 @@ bool FloodingRouter::shouldFilterReceived(MeshPacket *p)
return Router::shouldFilterReceived(p);
}
bool FloodingRouter::inRangeOfRouter()
{
uint32_t maximum_router_sec = 300;
// FIXME : Scale minimum_snr to accomodate different modem configurations.
float minimum_snr = 2;
for (int i = 0; i < myNodeInfo.router_count; i++) {
// A router has been seen and the heartbeat was heard within the last 300 seconds
if (
((myNodeInfo.router_sec[i] > 0) && (myNodeInfo.router_sec[i] < maximum_router_sec)) &&
(myNodeInfo.router_snr[i] > minimum_snr)
) {
return true;
}
}
return false;
}
void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{
bool rebroadcastPacket = true;
if (radioConfig.preferences.role == Role_Repeater || radioConfig.preferences.role == Role_Router) {
rebroadcastPacket = true;
} else if ((radioConfig.preferences.role == Role_Default) && inRangeOfRouter()) {
DEBUG_MSG("Role_Default - rx_snr > 13\n");
rebroadcastPacket = false;
}
if ((p->to == NODENUM_BROADCAST) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum() && rebroadcastPacket)) {
// If a broadcast, possibly _also_ send copies out into the mesh.
// (FIXME, do something smarter than naive flooding here)
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && getFrom(p) != getNodeNum()) {
if (p->id != 0) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it

View File

@@ -52,14 +52,6 @@ class FloodingRouter : public Router, protected PacketHistory
*/
virtual bool shouldFilterReceived(MeshPacket *p) override;
/**
* Are we in range of a router?
*
* "range" here may not be the right term.
* @return true if we're in range of a router
*/
virtual bool inRangeOfRouter();
/**
* Look for broadcasts we need to rebroadcast
*/

View File

@@ -3,15 +3,15 @@
#include "Channels.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "modules/RoutingModule.h"
#include "plugins/RoutingPlugin.h"
#include <assert.h>
std::vector<MeshPlugin *> *MeshPlugin::modules;
std::vector<MeshPlugin *> *MeshPlugin::plugins;
const MeshPacket *MeshPlugin::currentRequest;
/**
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
* the RoutingPlugin to avoid sending redundant acks
*/
MeshPacket *MeshPlugin::currentReply;
@@ -19,17 +19,17 @@ MeshPacket *MeshPlugin::currentReply;
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
{
// Can't trust static initalizer order, so we check each time
if (!modules)
modules = new std::vector<MeshPlugin *>();
if (!plugins)
plugins = new std::vector<MeshPlugin *>();
modules->push_back(this);
plugins->push_back(this);
}
void MeshPlugin::setup() {}
MeshPlugin::~MeshPlugin()
{
assert(0); // FIXME - remove from list of modules once someone needs this feature
assert(0); // FIXME - remove from list of plugins once someone needs this feature
}
MeshPacket *MeshPlugin::allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
@@ -68,10 +68,10 @@ MeshPacket *MeshPlugin::allocErrorResponse(Routing_Error err, const MeshPacket *
void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
{
// DEBUG_MSG("In call modules\n");
bool moduleFound = false;
// DEBUG_MSG("In call plugins\n");
bool pluginFound = false;
// We now allow **encrypted** packets to pass through the modules
// We now allow **encrypted** packets to pass through the plugins
bool isDecoded = mp.which_payloadVariant == MeshPacket_decoded_tag;
currentReply = NULL; // No reply yet
@@ -80,12 +80,12 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
auto ourNodeNum = nodeDB.getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
for (auto i = modules->begin(); i != modules->end(); ++i) {
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
pi.currentRequest = &mp;
/// We only call modules that are interested in the packet (and the message is destined to us or we are promiscious)
/// 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);
if ((src == RX_SRC_LOCAL) && !(pi.loopbackOk)) {
@@ -96,15 +96,15 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
if (wantsPacket) {
DEBUG_MSG("Module '%s' wantsPacket=%d\n", pi.name, wantsPacket);
DEBUG_MSG("Plugin '%s' wantsPacket=%d\n", pi.name, wantsPacket);
moduleFound = true;
pluginFound = true;
/// received channel (or NULL if not decoded)
Channel *ch = isDecoded ? &channels.getByIndex(mp.channel) : NULL;
/// Is the channel this packet arrived on acceptable? (security check)
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel modules
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel plugins
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and it needs to
/// to be able to fetch the initial admin packets without yet knowing any channels.
@@ -128,7 +128,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
ProcessMessage handled = pi.handleReceived(mp);
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious
// sniffing) also: we only let the one module send a reply, once that happens, remaining modules are not
// sniffing) also: we only let the one plugin send a reply, once that happens, remaining plugins are not
// considered
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary
@@ -137,9 +137,9 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
// any other node.
if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
pi.sendResponse(mp);
DEBUG_MSG("Module '%s' sent a response\n", pi.name);
DEBUG_MSG("Plugin '%s' sent a response\n", pi.name);
} else {
DEBUG_MSG("Module '%s' considered\n", pi.name);
DEBUG_MSG("Plugin '%s' considered\n", pi.name);
}
// If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks
@@ -150,7 +150,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
}
if (handled == ProcessMessage::STOP) {
DEBUG_MSG("Module '%s' handled and skipped other processing\n", pi.name);
DEBUG_MSG("Plugin '%s' handled and skipped other processing\n", pi.name);
break;
}
}
@@ -173,13 +173,13 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
// bad.
routingModule->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
routingPlugin->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
}
}
if (!moduleFound)
DEBUG_MSG("No modules interested in portnum=%d, src=%s\n",
mp.decoded.portnum,
if (!pluginFound)
DEBUG_MSG("No plugins interested in portnum=%d, src=%s\n",
mp.decoded.portnum,
(src == RX_SRC_LOCAL) ? "LOCAL":"REMOTE");
}
@@ -201,8 +201,8 @@ void MeshPlugin::sendResponse(const MeshPacket &req)
setReplyTo(r, req);
currentReply = r;
} else {
// Ignore - this is now expected behavior for routing module (because it ignores some replies)
// DEBUG_MSG("WARNING: Client requested response but this module did not provide\n");
// Ignore - this is now expected behavior for routing plugin (because it ignores some replies)
// DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
}
}
@@ -222,61 +222,31 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to)
p->decoded.request_id = to.id;
}
std::vector<MeshPlugin *> MeshPlugin::GetMeshModulesWithUIFrames()
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames()
{
std::vector<MeshPlugin *> modulesWithUIFrames;
if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
if (pi.wantUIFrame()) {
DEBUG_MSG("Module wants a UI Frame\n");
modulesWithUIFrames.push_back(&pi);
}
std::vector<MeshPlugin *> pluginsWithUIFrames;
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
if (pi.wantUIFrame()) {
DEBUG_MSG("Plugin wants a UI Frame\n");
pluginsWithUIFrames.push_back(&pi);
}
}
return modulesWithUIFrames;
return pluginsWithUIFrames;
}
void MeshPlugin::observeUIEvents(
Observer<const UIFrameEvent *> *observer)
{
if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
Observable<const UIFrameEvent *> *observable =
pi.getUIFrameObservable();
if (observable != NULL) {
DEBUG_MSG("Module wants a UI Frame\n");
observer->observe(observable);
}
std::vector<MeshPlugin *> pluginsWithUIFrames;
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
Observable<const UIFrameEvent *> *observable =
pi.getUIFrameObservable();
if (observable != NULL) {
DEBUG_MSG("Plugin wants a UI Frame\n");
observer->observe(observable);
}
}
}
AdminMessageHandleResult MeshPlugin::handleAdminMessageForAllPlugins(const MeshPacket &mp, AdminMessage *request, AdminMessage *response)
{
AdminMessageHandleResult handled = AdminMessageHandleResult::NOT_HANDLED;
if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
AdminMessageHandleResult h = pi.handleAdminMessageForModule(mp, request, response);
if (h == AdminMessageHandleResult::HANDLED_WITH_RESPONSE)
{
// In case we have a response it always has priority.
DEBUG_MSG("Reply prepared by module '%s' of variant: %d\n",
pi.name,
response->which_variant);
handled = h;
}
else if ((handled != AdminMessageHandleResult::HANDLED_WITH_RESPONSE) &&
(h == AdminMessageHandleResult::HANDLED))
{
// In case the message is handled it should be populated, but will not overwrite
// a result with response.
handled = h;
}
}
}
return handled;
}

View File

@@ -21,19 +21,6 @@ enum class ProcessMessage
STOP = 1,
};
/**
* Used by modules to return the result of the AdminMessage handling.
* If request is handled, then module should return HANDLED,
* If response is also prepared for the request, then HANDLED_WITH_RESPONSE
* should be returned.
*/
enum class AdminMessageHandleResult
{
NOT_HANDLED = 0,
HANDLED = 1,
HANDLED_WITH_RESPONSE = 2,
};
/*
* This struct is used by Screen to figure out whether screen frame should be updated.
*/
@@ -42,19 +29,19 @@ typedef struct _UIFrameEvent {
bool needRedraw;
} UIFrameEvent;
/** A baseclass for any mesh "module".
/** A baseclass for any mesh "plugin".
*
* A module allows you to add new features to meshtastic device code, without needing to know messaging details.
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
*
* A key concept for this is that your module should use a particular "portnum" for each message type you want to receive
* A key concept for this is that your plugin should use a particular "portnum" for each message type you want to receive
* and handle.
*
* Interally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
* can use these classes as examples for how to write your own custom module. See here: (FIXME)
* Interally we use plugins to implement the core meshtastic text messaging and gps position sharing features. You
* can use these classes as examples for how to write your own custom plugin. See here: (FIXME)
*/
class MeshPlugin
{
static std::vector<MeshPlugin *> *modules;
static std::vector<MeshPlugin *> *plugins;
public:
/** Constructor
@@ -68,27 +55,25 @@ class MeshPlugin
*/
static void callPlugins(const MeshPacket &mp, RxSource src = RX_SRC_RADIO);
static std::vector<MeshPlugin *> GetMeshModulesWithUIFrames();
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
static AdminMessageHandleResult handleAdminMessageForAllPlugins(
const MeshPacket &mp, AdminMessage *request, AdminMessage *response);
#ifndef NO_SCREEN
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
#endif
protected:
const char *name;
/** Most modules only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
/** Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those
modules can set this to true and their handleReceived() will be called for every packet.
plugins can set this to true and their handleReceived() will be called for every packet.
*/
bool isPromiscuous = false;
/** Also receive a copy of LOCALLY GENERATED messages - most modules should leave
/** Also receive a copy of LOCALLY GENERATED messages - most plugins should leave
* this setting disabled - see issue #877 */
bool loopbackOk = false;
/** Most modules only understand decrypted packets. For modules that also want to see encrypted packets, they should set this
/** Most plugins only understand decrypted packets. For plugins that also want to see encrypted packets, they should set this
* flag */
bool encryptedOk = false;
@@ -101,11 +86,11 @@ class MeshPlugin
const char *boundChannel = NULL;
/**
* If this module is currently handling a request currentRequest will be preset
* If this plugin is currently handling a request currentRequest will be preset
* to the packet with the request. This is mostly useful for reply handlers.
*
* Note: this can be static because we are guaranteed to be processing only one
* plumodulegin at a time.
* plugin at a time.
*/
static const MeshPacket *currentRequest;
@@ -115,7 +100,7 @@ class MeshPlugin
MeshPacket *myReply = NULL;
/**
* Initialize your module. This setup function is called once after all hardware and mesh protocol layers have
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
* been initialized
*/
virtual void setup();
@@ -150,23 +135,10 @@ class MeshPlugin
/// Send an error response for the specified packet.
MeshPacket *allocErrorResponse(Routing_Error err, const MeshPacket *p);
/**
* @brief An admin message arrived to AdminModule. Module was asked whether it want to handle the request.
*
* @param mp The mesh packet arrived.
* @param request The AdminMessage request extracted from the packet.
* @param response The prepared response
* @return AdminMessageHandleResult
* HANDLED if message was handled
* HANDLED_WITH_RESPONSE if a response is also prepared and to be sent.
*/
virtual AdminMessageHandleResult handleAdminMessageForModule(
const MeshPacket &mp, AdminMessage *request, AdminMessage *response) { return AdminMessageHandleResult::NOT_HANDLED; };
private:
/**
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
* the RoutingModule to avoid sending redundant acks
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
* the RoutingPlugin to avoid sending redundant acks
*/
static MeshPacket *currentReply;

View File

@@ -8,13 +8,10 @@
// Map from old region names to new region enums
struct RegionInfo {
RegionCode code;
float freqStart;
float freqEnd;
float dutyCycle;
float spacing;
uint8_t numChannels;
uint8_t powerLimit; // Or zero for not set
bool audioPermitted;
bool freqSwitching;
float freq;
float spacing;
const char *name; // EU433 etc
};

View File

@@ -12,8 +12,8 @@
#include "RTC.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h"
#include "plugins/NodeInfoPlugin.h"
#include "plugins/PositionPlugin.h"
#include "power.h"
/*
@@ -71,17 +71,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
fromNum++;
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
MeshPacket *copied = packetPool.allocCopy(*mp);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
sendToPhone((MeshPacket *)mp);
return 0;
}
@@ -115,10 +105,10 @@ void MeshService::reloadOwner()
// DEBUG_MSG("reloadOwner()\n");
// update our local data directly
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
assert(nodeInfoModule);
assert(nodeInfoPlugin);
// update everyone else
if (nodeInfoModule)
nodeInfoModule->sendOurNodeInfo();
if (nodeInfoPlugin)
nodeInfoPlugin->sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -161,12 +151,16 @@ bool MeshService::cancelSending(PacketId id)
return router->cancelSending(nodeDB.getNodeNum(), id);
}
void MeshService::sendToMesh(MeshPacket *p, RxSource src)
void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone)
{
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
router->sendLocal(p, src);
if (ccToPhone) {
sendToPhone(p);
}
}
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
@@ -175,14 +169,14 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
assert(node);
if (node->has_position) {
if (positionModule) {
if (positionPlugin) {
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
positionModule->sendOurPosition(dest, wantReplies);
positionPlugin->sendOurPosition(dest, wantReplies);
}
} else {
if (nodeInfoModule) {
if (nodeInfoPlugin) {
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
nodeInfoModule->sendOurNodeInfo(dest, wantReplies);
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
}
}
@@ -213,6 +207,20 @@ NodeInfo *MeshService::refreshMyNodeInfo()
return node;
}
void MeshService::sendToPhone(MeshPacket *p) {
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
MeshPacket *copied = packetPool.allocCopy(*p);
perhapsDecode(copied);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
fromNum++;
}
int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
{
// Update our local node info with our position (even if we don't decide to update anyone else)

View File

@@ -75,7 +75,7 @@ class MeshService
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
/// cache
void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL);
void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL, bool ccToPhone = false);
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool cancelSending(PacketId id);
@@ -83,6 +83,9 @@ class MeshService
/// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo();
/// Send a packet to the phone
void sendToPhone(MeshPacket *p);
private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing
@@ -91,7 +94,7 @@ class MeshService
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
/// needs to keep the packet around it makes a copy
int handleFromRadio(const MeshPacket *p);
friend class RoutingModule;
friend class RoutingPlugin;
};
extern MeshService service;

View File

@@ -1,6 +1,8 @@
#include "configuration.h"
#include <assert.h>
#include "FS.h"
#include "Channels.h"
#include "CryptoEngine.h"
#include "FSCommon.h"
@@ -19,7 +21,7 @@
#ifndef NO_ESP32
#include "mesh/http/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h"
#include "plugins/esp32/StoreForwardPlugin.h"
#include <Preferences.h>
#include <nvs_flash.h>
#endif
@@ -95,14 +97,23 @@ bool NodeDB::resetRadioConfig()
nvs_flash_erase();
#endif
#ifdef NRF52_SERIES
Bluefruit.begin();
DEBUG_MSG("Clearing bluetooth bonds!\n");
bond_print_list(BLE_GAP_ROLE_PERIPH);
bond_print_list(BLE_GAP_ROLE_CENTRAL);
// first, remove the "/prefs" (this removes most prefs)
FS.rmdir_r("/prefs");
// second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState();
// third, write to disk
saveToDisk();
Bluefruit.begin();
DEBUG_MSG("Clearing bluetooth bonds!\n");
bond_print_list(BLE_GAP_ROLE_PERIPH);
bond_print_list(BLE_GAP_ROLE_CENTRAL);
Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds();
Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds();
#endif
didFactoryReset = true;
}
@@ -227,8 +238,35 @@ void NodeDB::init()
info->user = owner;
info->has_user = true;
// removed from 1.2 (though we do use old values if found)
// We set these _after_ loading from disk - because they come from the build and are more trusted than
// what is stored in flash
// if (xstr(HW_VERSION)[0])
// strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
// else DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build
// flag
// DEBUG_MSG("legacy region %d\n", devicestate.legacyRadio.preferences.region);
if (radioConfig.preferences.region == RegionCode_Unset)
radioConfig.preferences.region = devicestate.legacyRadio.preferences.region;
// Check for the old style of region code strings, if found, convert to the new enum.
// Those strings will look like "1.0-EU433"
if (radioConfig.preferences.region == RegionCode_Unset && strncmp(myNodeInfo.region, "1.0-", 4) == 0) {
const char *regionStr = myNodeInfo.region + 4; // EU433 or whatever
for (const RegionInfo *r = regions; r->code != RegionCode_Unset; r++)
if (strcmp(r->name, regionStr) == 0) {
radioConfig.preferences.region = r->code;
break;
}
}
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
// hw_model is no longer stored in myNodeInfo (as of 1.2.11) - we now store it as an enum in nodeinfo
myNodeInfo.hw_model_deprecated[0] = '\0';
// strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model));
#ifndef NO_ESP32
Preferences preferences;
preferences.begin("meshtastic", false);
@@ -283,16 +321,16 @@ static const char *channelfile = "/prefs/channels.proto";
/** Load a protobuf from a file, return true for success */
bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
{
#ifdef FSCom
#ifdef FS
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
auto f = FSCom.open(filename);
auto f = FS.open(filename);
// FIXME, temporary hack until every node in the universe is 1.2 or later - look for prefs in the old location (so we can
// preserve region)
if (!f && filename == preffile) {
filename = preffileOld;
f = FSCom.open(filename);
f = FS.open(filename);
}
bool okay = false;
@@ -345,11 +383,11 @@ void NodeDB::loadFromDisk()
/** Save a protobuf from a file, return true for success */
bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct)
{
#ifdef FSCom
#ifdef FS
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
String filenameTmp = filename;
filenameTmp += ".tmp";
auto f = FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
auto f = FS.open(filenameTmp.c_str(), FILE_O_WRITE);
bool okay = false;
if (f) {
DEBUG_MSG("Saving %s\n", filename);
@@ -364,9 +402,9 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
f.close();
// brief window of risk here ;-)
if (!FSCom.remove(filename))
if (!FS.remove(filename))
DEBUG_MSG("Warning: Can't remove old pref file\n");
if (!FSCom.rename(filenameTmp.c_str(), filename))
if (!FS.rename(filenameTmp.c_str(), filename))
DEBUG_MSG("Error: can't rename new pref file\n");
} else {
DEBUG_MSG("Can't write prefs\n");
@@ -380,8 +418,8 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
void NodeDB::saveChannelsToDisk()
{
if (!devicestate.no_save) {
#ifdef FSCom
FSCom.mkdir("/prefs");
#ifdef FS
FS.mkdir("/prefs");
#endif
saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile);
}
@@ -390,15 +428,15 @@ void NodeDB::saveChannelsToDisk()
void NodeDB::saveToDisk()
{
if (!devicestate.no_save) {
#ifdef FSCom
FSCom.mkdir("/prefs");
#ifdef FS
FS.mkdir("/prefs");
#endif
saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
saveChannelsToDisk();
// remove any pre 1.2 pref files, turn on after 1.2 is in beta
// if(okay) FSCom.remove(preffileOld);
// if(okay) FS.remove(preffileOld);
} else {
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
}
@@ -451,11 +489,11 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
if (src == RX_SRC_LOCAL) {
// Local packet, fully authoritative
DEBUG_MSG("updatePosition LOCAL pos@%x:5, time=%u, latI=%d, lonI=%d\n",
DEBUG_MSG("updatePosition LOCAL pos@%x:5, time=%u, latI=%d, lonI=%d\n",
p.pos_timestamp, p.time, p.latitude_i, p.longitude_i);
info->position = p;
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.pos_timestamp &&
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.pos_timestamp &&
!p.location_source) {
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900)
@@ -468,7 +506,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
// recorded based on the packet rxTime
//
// FIXME perhaps handle RX_SRC_USER separately?
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n",
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n",
nodeId, p.time, p.latitude_i, p.longitude_i);
// First, back up fields that we want to protect from overwrite

View File

@@ -1,3 +1,4 @@
#include "configuration.h"
#include "PhoneAPI.h"
#include "Channels.h"
#include "GPS.h"
@@ -5,7 +6,6 @@
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
#include "configuration.h"
#include <assert.h>
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE

View File

@@ -24,7 +24,6 @@ class PhoneAPI
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
// (disconnected)
STATE_SEND_MY_INFO, // send our my info record
STATE_SEND_GROUPS,
// STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet
// STATE_SEND_OWNER, no need to send Owner specially, it is just part of the nodedb
STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
@@ -59,7 +58,7 @@ class PhoneAPI
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
void close();
virtual void close();
/**
* Handle a ToRadio protobuf

View File

@@ -2,10 +2,10 @@
#include "SinglePortPlugin.h"
/**
* A base class for mesh modules that assume that they are sending/receiving one particular protobuf based
* A base class for mesh plugins that assume that they are sending/receiving one particular protobuf based
* payload. Using one particular app ID.
*
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your module
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your plugin
* and avoid a bunch of boilerplate code.
*/
template <class T> class ProtobufPlugin : protected SinglePortPlugin
@@ -67,7 +67,7 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
decoded = &scratch;
else
DEBUG_MSG("Error decoding protobuf module!\n");
DEBUG_MSG("Error decoding protobuf plugin!\n");
}
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;

View File

@@ -140,8 +140,6 @@ bool RF95Interface::reconfigure()
void RF95Interface::addReceiveMetadata(MeshPacket *mp)
{
mp->rx_snr = lora->getSNR();
mp->rx_rssi = lround(lora->getRSSI());
}
void RF95Interface::setStandby()

View File

@@ -1,3 +1,4 @@
#include "configuration.h"
#include "RadioInterface.h"
#include "Channels.h"
#include "MeshRadio.h"
@@ -5,95 +6,45 @@
#include "NodeDB.h"
#include "Router.h"
#include "assert.h"
#include "configuration.h"
#include "sleep.h"
#include <assert.h>
#include <pb_decode.h>
#include <pb_encode.h>
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \
#define RDEF(name, freq, spacing, num_ch, power_limit) \
{ \
RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, #name \
RegionCode_##name, num_ch, power_limit, freq, spacing, #name \
}
const RegionInfo regions[] = {
/*
https://link.springer.com/content/pdf/bbm%3A978-1-4842-4357-2%2F1.pdf
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
*/
RDEF(US, 902.0f, 928.0f, 100, 0, 30, true, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(EU433, 433.0f, 434.0f, 10, 0, 12, true, false),
/*
https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
https://www.legislation.gov.uk/uksi/1999/930/schedule/6/part/III/made/data.xht?view=snippet&wrap=true
audio_permitted = false per regulation
*/
RDEF(EU868, 869.4f, 869.65f, 10, 0, 16, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(CN, 470.0f, 510.0f, 100, 0, 19, true, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(JP, 920.8f, 927.8f, 100, 0, 16, true, false),
/*
https://www.iot.org.au/wp/wp-content/uploads/2016/12/IoTSpectrumFactSheet.pdf
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
*/
RDEF(ANZ, 915.0f, 928.0f, 100, 0, 30, true, false),
/*
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf
Note:
- We do LBT, so 100% is allowed.
*/
RDEF(RU, 868.7f, 869.2f, 100, 0, 20, true, false),
/*
???
*/
RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false),
/*
???
*/
RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(IN, 865.0f, 867.0f, 100, 0, 30, true, false),
/*
https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
*/
RDEF(NZ865, 864.0f, 868.0f, 100, 0, 0, true, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
RDEF(TH, 920.0f, 925.0f, 100, 0, 16, true, false),
/*
This needs to be last. Same as US.
*/
RDEF(Unset, 902.0f, 928.0f, 100, 0, 30, true, false)
RDEF(US, 903.08f, 2.16f, 13, 0), RDEF(EU433, 433.175f, 0.2f, 8, 0), RDEF(EU865, 865.2f, 0.3f, 10, 0),
RDEF(CN, 470.0f, 2.0f, 20, 0),
RDEF(JP, 920.0f, 0.5f, 10, 13), // See https://github.com/meshtastic/Meshtastic-device/issues/346 power level 13
RDEF(ANZ, 916.0f, 0.5f, 20, 0), // AU/NZ channel settings 915-928MHz
RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel
// freq. (921.9f is for download, others are for uplink)
RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz)
RDEF(RU, 868.9f, 0.2f, 2, 20), // See notes below
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
};
/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2):
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018)
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1 We have 3 options for 868 MHz:
864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports.
866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports
868,7 - 869,2 MHz ERP 100mW, Duty Cycle 10% or LBT, no resctrictions
and according to RP2-1.0.2 LoRaWAN® Regional Parameters RP2-1.0.2 LoRaWAN® Regional Parameters - LoRa Alliance®
I propose to use following meshtastic bandplan:
1 channel - central frequency 868.9MHz 125kHz band
Protective band - 75kHz
2 channel - central frequency 869.1MHz 125kHz band
RDEF(RU, 868.9f, 0.2f, 2, 20)
*/
const RegionInfo *myRegion;
void initRegion()
@@ -103,6 +54,8 @@ void initRegion()
;
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_bands = myRegion->numChannels; // Tell our android app how many channels we have
}
/**
@@ -219,9 +172,6 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (p->rx_snr != 0.0) {
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
}
if (p->rx_rssi != 0) {
DEBUG_MSG(" rxSNR=%g", p->rx_rssi);
}
if (p->priority != 0)
DEBUG_MSG(" priority=%d", p->priority);
@@ -324,40 +274,38 @@ void RadioInterface::applyModemConfig()
auto channelSettings = channels.getPrimary();
if (channelSettings.spread_factor == 0) {
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_ShortFast:
bw = 250;
cr = 8;
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
///< range
bw = 125;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_ShortSlow:
bw = 250;
cr = 8;
sf = 8;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
///< range
bw = 500;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_MidFast:
bw = 250;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
///< range
bw = 31.25;
cr = 8;
sf = 9;
break;
case ChannelSettings_ModemConfig_MidSlow:
bw = 250;
cr = 8;
sf = 10;
break;
case ChannelSettings_ModemConfig_LongFast:
bw = 250;
cr = 8;
sf = 11;
break;
case ChannelSettings_ModemConfig_LongSlow:
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
bw = 125;
cr = 8;
sf = 12;
break;
case ChannelSettings_ModemConfig_VLongSlow:
bw = 31.25;
cr = 8;
sf = 12;
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
bw = 250;
cr = 6;
sf = 11;
break;
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
bw = 250;
cr = 7;
sf = 10;
break;
default:
assert(0); // Unknown enum
@@ -374,26 +322,25 @@ void RadioInterface::applyModemConfig()
}
power = channelSettings.tx_power;
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
assert(myRegion); // Should have been found in init
// Calculate the number of channels
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
assert(myRegion); // Should have been found in init
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
const char *channelName = channels.getName(channels.getPrimaryIndex());
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % numChannels;
float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels;
float freq = myRegion->freq + radioConfig.preferences.frequency_offset + myRegion->spacing * channel_num;
saveChannelNum(channel_num);
saveFreq(freq);
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd,
myRegion->freqEnd - myRegion->freqStart);
DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels);
DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", getFreq());
DEBUG_MSG("Radio frequency: %f\n", getFreq()); // the frequency could be overridden in RadioInterface::getFreq() for some modules
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
}
@@ -457,4 +404,4 @@ size_t RadioInterface::beginSending(MeshPacket *p)
sendingPacket = p;
return p->encrypted.size + sizeof(PacketHeader);
}
}

View File

@@ -6,7 +6,7 @@
#include "RTC.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "modules/RoutingModule.h"
#include "plugins/RoutingPlugin.h"
#if defined(HAS_WIFI) || defined(PORTDUINO)
#include "mqtt/MQTT.h"
@@ -132,7 +132,7 @@ MeshPacket *Router::allocForSending()
*/
void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
{
routingModule->sendAckNak(err, to, idFrom, chIndex);
routingPlugin->sendAckNak(err, to, idFrom, chIndex);
}
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
@@ -276,7 +276,7 @@ bool perhapsDecode(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag)
return true; // If packet was already decoded just return
assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
//assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
// Try to find a channel that works with this hash
for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) {
@@ -376,7 +376,7 @@ void Router::handleReceived(MeshPacket *p, RxSource src)
printPacket("packet decoding failed (no PSK?)", p);
}
// call modules here
// call plugins here
MeshPlugin::callPlugins(*p, src);
}

View File

@@ -71,7 +71,7 @@ class Router : protected concurrency::OSThread
void enqueueReceivedMessage(MeshPacket *p);
protected:
friend class RoutingModule;
friend class RoutingPlugin;
/**
* Send a packet on a suitable interface. This routine will
@@ -85,7 +85,7 @@ class Router : protected concurrency::OSThread
/**
* Should this incoming filter be dropped?
*
* FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic
* FIXME, move this into the new RoutingPlugin and do the filtering there using the regular plugin logic
*
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet

View File

@@ -65,7 +65,7 @@ bool SX126xInterface<T>::init()
#ifdef SX126X_TXEN
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
if (res == ERR_NONE)
res = lora.setDio2AsRfSwitch(false);
res = lora.setDio2AsRfSwitch(true);
#endif
#if 0
@@ -129,9 +129,6 @@ bool SX126xInterface<T>::reconfigure()
err = lora.setSyncWord(syncWord);
assert(err == ERR_NONE);
err = lora.setCurrentLimit(currentLimit);
assert(err == ERR_NONE);
err = lora.setPreambleLength(preambleLength);
assert(err == ERR_NONE);
@@ -139,11 +136,11 @@ bool SX126xInterface<T>::reconfigure()
if (err != ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
if (power > 22) // This chip has lower power limits than some
power = 22;
if (power > SX126X_MAX_POWER) // This chip has lower power limits than some
power = SX126X_MAX_POWER;
err = lora.setOutputPower(power);
assert(err == ERR_NONE);
startReceive(); // restart receiving
return ERR_NONE;
@@ -191,7 +188,11 @@ void SX126xInterface<T>::addReceiveMetadata(MeshPacket *mp)
template<typename T>
void SX126xInterface<T>::configHardwareForSend()
{
#ifdef SX126X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
// If we have RXEN/TXEN control - turn on TX power / off RX power
#ifdef SX126X_RXEN
digitalWrite(SX126X_RXEN, LOW);
#endif
#ifdef SX126X_TXEN
digitalWrite(SX126X_TXEN, HIGH);
#endif
@@ -210,7 +211,11 @@ void SX126xInterface<T>::startReceive()
setStandby();
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
// If we have RXEN/TXEN control - turn on RX power / off TX power
#ifdef SX126X_TXEN
digitalWrite(SX126X_TXEN, LOW);
#endif
#ifdef SX126X_RXEN
digitalWrite(SX126X_RXEN, HIGH);
#endif

View File

@@ -3,7 +3,7 @@
#include "Router.h"
/**
* Most modules are only interested in sending/receving one particular portnum. This baseclass simplifies that common
* Most plugins are only interested in sending/receving one particular portnum. This baseclass simplifies that common
* case.
*/
class SinglePortPlugin : public MeshPlugin

View File

@@ -29,18 +29,18 @@ typedef struct _AdminMessage {
bool confirm_set_radio;
bool exit_simulator;
int32_t reboot_seconds;
bool get_canned_message_module_part1_request;
char get_canned_message_module_part1_response[201];
bool get_canned_message_module_part2_request;
char get_canned_message_module_part2_response[201];
bool get_canned_message_module_part3_request;
char get_canned_message_module_part3_response[201];
bool get_canned_message_module_part4_request;
char get_canned_message_module_part4_response[201];
char set_canned_message_module_part1[201];
char set_canned_message_module_part2[201];
char set_canned_message_module_part3[201];
char set_canned_message_module_part4[201];
bool get_canned_message_plugin_part1_request;
char get_canned_message_plugin_part1_response[201];
bool get_canned_message_plugin_part2_request;
char get_canned_message_plugin_part2_response[201];
bool get_canned_message_plugin_part3_request;
char get_canned_message_plugin_part3_response[201];
bool get_canned_message_plugin_part4_request;
char get_canned_message_plugin_part4_response[201];
char set_canned_message_plugin_part1[201];
char set_canned_message_plugin_part2[201];
char set_canned_message_plugin_part3[201];
char set_canned_message_plugin_part4[201];
int32_t shutdown_seconds;
};
} AdminMessage;
@@ -68,18 +68,18 @@ extern "C" {
#define AdminMessage_confirm_set_radio_tag 33
#define AdminMessage_exit_simulator_tag 34
#define AdminMessage_reboot_seconds_tag 35
#define AdminMessage_get_canned_message_module_part1_request_tag 36
#define AdminMessage_get_canned_message_module_part1_response_tag 37
#define AdminMessage_get_canned_message_module_part2_request_tag 38
#define AdminMessage_get_canned_message_module_part2_response_tag 39
#define AdminMessage_get_canned_message_module_part3_request_tag 40
#define AdminMessage_get_canned_message_module_part3_response_tag 41
#define AdminMessage_get_canned_message_module_part4_request_tag 42
#define AdminMessage_get_canned_message_module_part4_response_tag 43
#define AdminMessage_set_canned_message_module_part1_tag 44
#define AdminMessage_set_canned_message_module_part2_tag 45
#define AdminMessage_set_canned_message_module_part3_tag 46
#define AdminMessage_set_canned_message_module_part4_tag 47
#define AdminMessage_get_canned_message_plugin_part1_request_tag 36
#define AdminMessage_get_canned_message_plugin_part1_response_tag 37
#define AdminMessage_get_canned_message_plugin_part2_request_tag 38
#define AdminMessage_get_canned_message_plugin_part2_response_tag 39
#define AdminMessage_get_canned_message_plugin_part3_request_tag 40
#define AdminMessage_get_canned_message_plugin_part3_response_tag 41
#define AdminMessage_get_canned_message_plugin_part4_request_tag 42
#define AdminMessage_get_canned_message_plugin_part4_response_tag 43
#define AdminMessage_set_canned_message_plugin_part1_tag 44
#define AdminMessage_set_canned_message_plugin_part2_tag 45
#define AdminMessage_set_canned_message_plugin_part3_tag 46
#define AdminMessage_set_canned_message_plugin_part4_tag 47
#define AdminMessage_shutdown_seconds_tag 51
/* Struct field encoding specification for nanopb */
@@ -97,18 +97,18 @@ X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_chan
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \
X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \
X(a, STATIC, ONEOF, INT32, (variant,reboot_seconds,reboot_seconds), 35) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part1_request,get_canned_message_module_part1_request), 36) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part1_response,get_canned_message_module_part1_response), 37) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part2_request,get_canned_message_module_part2_request), 38) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part2_response,get_canned_message_module_part2_response), 39) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part3_request,get_canned_message_module_part3_request), 40) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part3_response,get_canned_message_module_part3_response), 41) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part4_request,get_canned_message_module_part4_request), 42) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part4_response,get_canned_message_module_part4_response), 43) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part1,set_canned_message_module_part1), 44) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part2,set_canned_message_module_part2), 45) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part3,set_canned_message_module_part3), 46) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part4,set_canned_message_module_part4), 47) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_plugin_part1_request,get_canned_message_plugin_part1_request), 36) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_plugin_part1_response,get_canned_message_plugin_part1_response), 37) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_plugin_part2_request,get_canned_message_plugin_part2_request), 38) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_plugin_part2_response,get_canned_message_plugin_part2_response), 39) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_plugin_part3_request,get_canned_message_plugin_part3_request), 40) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_plugin_part3_response,get_canned_message_plugin_part3_response), 41) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_plugin_part4_request,get_canned_message_plugin_part4_request), 42) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_plugin_part4_response,get_canned_message_plugin_part4_response), 43) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_plugin_part1,set_canned_message_plugin_part1), 44) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_plugin_part2,set_canned_message_plugin_part2), 45) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_plugin_part3,set_canned_message_plugin_part3), 46) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_plugin_part4,set_canned_message_plugin_part4), 47) \
X(a, STATIC, ONEOF, INT32, (variant,shutdown_seconds,shutdown_seconds), 51)
#define AdminMessage_CALLBACK NULL
#define AdminMessage_DEFAULT NULL
@@ -125,7 +125,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
#define AdminMessage_fields &AdminMessage_msg
/* Maximum encoded size of messages (where known) */
#define AdminMessage_size 611
#define AdminMessage_size 804
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -6,7 +6,7 @@
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(CannedMessageModuleConfig, CannedMessageModuleConfig, 2)
PB_BIND(CannedMessagePluginConfig, CannedMessagePluginConfig, 2)

View File

@@ -10,12 +10,12 @@
#endif
/* Struct definitions */
typedef struct _CannedMessageModuleConfig {
typedef struct _CannedMessagePluginConfig {
char messagesPart1[201];
char messagesPart2[201];
char messagesPart3[201];
char messagesPart4[201];
} CannedMessageModuleConfig;
} CannedMessagePluginConfig;
#ifdef __cplusplus
@@ -23,31 +23,31 @@ extern "C" {
#endif
/* Initializer values for message structs */
#define CannedMessageModuleConfig_init_default {"", "", "", ""}
#define CannedMessageModuleConfig_init_zero {"", "", "", ""}
#define CannedMessagePluginConfig_init_default {"", "", "", ""}
#define CannedMessagePluginConfig_init_zero {"", "", "", ""}
/* Field tags (for use in manual encoding/decoding) */
#define CannedMessageModuleConfig_messagesPart1_tag 11
#define CannedMessageModuleConfig_messagesPart2_tag 12
#define CannedMessageModuleConfig_messagesPart3_tag 13
#define CannedMessageModuleConfig_messagesPart4_tag 14
#define CannedMessagePluginConfig_messagesPart1_tag 11
#define CannedMessagePluginConfig_messagesPart2_tag 12
#define CannedMessagePluginConfig_messagesPart3_tag 13
#define CannedMessagePluginConfig_messagesPart4_tag 14
/* Struct field encoding specification for nanopb */
#define CannedMessageModuleConfig_FIELDLIST(X, a) \
#define CannedMessagePluginConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, messagesPart1, 11) \
X(a, STATIC, SINGULAR, STRING, messagesPart2, 12) \
X(a, STATIC, SINGULAR, STRING, messagesPart3, 13) \
X(a, STATIC, SINGULAR, STRING, messagesPart4, 14)
#define CannedMessageModuleConfig_CALLBACK NULL
#define CannedMessageModuleConfig_DEFAULT NULL
#define CannedMessagePluginConfig_CALLBACK NULL
#define CannedMessagePluginConfig_DEFAULT NULL
extern const pb_msgdesc_t CannedMessageModuleConfig_msg;
extern const pb_msgdesc_t CannedMessagePluginConfig_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define CannedMessageModuleConfig_fields &CannedMessageModuleConfig_msg
#define CannedMessagePluginConfig_fields &CannedMessagePluginConfig_msg
/* Maximum encoded size of messages (where known) */
#define CannedMessageModuleConfig_size 812
#define CannedMessagePluginConfig_size 812
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -11,13 +11,12 @@
/* Enum definitions */
typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_VLongSlow = 0,
ChannelSettings_ModemConfig_LongSlow = 1,
ChannelSettings_ModemConfig_LongFast = 2,
ChannelSettings_ModemConfig_MidSlow = 3,
ChannelSettings_ModemConfig_MidFast = 4,
ChannelSettings_ModemConfig_ShortSlow = 5,
ChannelSettings_ModemConfig_ShortFast = 6
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
ChannelSettings_ModemConfig_Bw31_25Cr48Sf512 = 2,
ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3,
ChannelSettings_ModemConfig_Bw250Cr46Sf2048 = 4,
ChannelSettings_ModemConfig_Bw250Cr47Sf1024 = 5
} ChannelSettings_ModemConfig;
typedef enum _Channel_Role {
@@ -51,9 +50,9 @@ typedef struct _Channel {
/* Helper constants for enums */
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_VLongSlow
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_ShortFast
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_ShortFast+1))
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw250Cr47Sf1024
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw250Cr47Sf1024+1))
#define _Channel_Role_MIN Channel_Role_DISABLED
#define _Channel_Role_MAX Channel_Role_SECONDARY

View File

@@ -6,6 +6,12 @@
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(LegacyRadioConfig, LegacyRadioConfig, AUTO)
PB_BIND(LegacyRadioConfig_LegacyPreferences, LegacyRadioConfig_LegacyPreferences, AUTO)
PB_BIND(DeviceState, DeviceState, 4)

View File

@@ -6,6 +6,7 @@
#include <pb.h>
#include "channel.pb.h"
#include "mesh.pb.h"
#include "radioconfig.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
@@ -17,7 +18,18 @@ typedef struct _ChannelFile {
Channel channels[8];
} ChannelFile;
typedef struct _LegacyRadioConfig_LegacyPreferences {
RegionCode region;
} LegacyRadioConfig_LegacyPreferences;
typedef struct _LegacyRadioConfig {
bool has_preferences;
LegacyRadioConfig_LegacyPreferences preferences;
} LegacyRadioConfig;
typedef struct _DeviceState {
bool has_legacyRadio;
LegacyRadioConfig legacyRadio;
bool has_my_node;
MyNodeInfo my_node;
bool has_owner;
@@ -39,13 +51,20 @@ extern "C" {
#endif
/* Initializer values for message structs */
#define DeviceState_init_default {false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
#define LegacyRadioConfig_init_default {false, LegacyRadioConfig_LegacyPreferences_init_default}
#define LegacyRadioConfig_LegacyPreferences_init_default {_RegionCode_MIN}
#define DeviceState_init_default {false, LegacyRadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
#define ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}}
#define DeviceState_init_zero {false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
#define LegacyRadioConfig_init_zero {false, LegacyRadioConfig_LegacyPreferences_init_zero}
#define LegacyRadioConfig_LegacyPreferences_init_zero {_RegionCode_MIN}
#define DeviceState_init_zero {false, LegacyRadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
#define ChannelFile_init_zero {0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelFile_channels_tag 1
#define LegacyRadioConfig_LegacyPreferences_region_tag 15
#define LegacyRadioConfig_preferences_tag 1
#define DeviceState_legacyRadio_tag 1
#define DeviceState_my_node_tag 2
#define DeviceState_owner_tag 3
#define DeviceState_node_db_tag 4
@@ -56,7 +75,19 @@ extern "C" {
#define DeviceState_did_gps_reset_tag 11
/* Struct field encoding specification for nanopb */
#define LegacyRadioConfig_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1)
#define LegacyRadioConfig_CALLBACK NULL
#define LegacyRadioConfig_DEFAULT NULL
#define LegacyRadioConfig_preferences_MSGTYPE LegacyRadioConfig_LegacyPreferences
#define LegacyRadioConfig_LegacyPreferences_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, region, 15)
#define LegacyRadioConfig_LegacyPreferences_CALLBACK NULL
#define LegacyRadioConfig_LegacyPreferences_DEFAULT NULL
#define DeviceState_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, legacyRadio, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \
X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \
X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
@@ -67,6 +98,7 @@ X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11)
#define DeviceState_CALLBACK NULL
#define DeviceState_DEFAULT NULL
#define DeviceState_legacyRadio_MSGTYPE LegacyRadioConfig
#define DeviceState_my_node_MSGTYPE MyNodeInfo
#define DeviceState_owner_MSGTYPE User
#define DeviceState_node_db_MSGTYPE NodeInfo
@@ -79,15 +111,21 @@ X(a, STATIC, REPEATED, MESSAGE, channels, 1)
#define ChannelFile_DEFAULT NULL
#define ChannelFile_channels_MSGTYPE Channel
extern const pb_msgdesc_t LegacyRadioConfig_msg;
extern const pb_msgdesc_t LegacyRadioConfig_LegacyPreferences_msg;
extern const pb_msgdesc_t DeviceState_msg;
extern const pb_msgdesc_t ChannelFile_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define LegacyRadioConfig_fields &LegacyRadioConfig_msg
#define LegacyRadioConfig_LegacyPreferences_fields &LegacyRadioConfig_LegacyPreferences_msg
#define DeviceState_fields &DeviceState_msg
#define ChannelFile_fields &ChannelFile_msg
/* Maximum encoded size of messages (where known) */
#define DeviceState_size 9885
#define LegacyRadioConfig_size 4
#define LegacyRadioConfig_LegacyPreferences_size 2
#define DeviceState_size 10002
#define ChannelFile_size 832
#ifdef __cplusplus

View File

@@ -1,12 +1,12 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.4 */
#include "telemetry.pb.h"
#include "environmental_measurement.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(Telemetry, Telemetry, AUTO)
PB_BIND(EnvironmentalMeasurement, EnvironmentalMeasurement, AUTO)

View File

@@ -1,8 +1,8 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_TELEMETRY_PB_H_INCLUDED
#define PB_TELEMETRY_PB_H_INCLUDED
#ifndef PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
#define PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
@@ -10,14 +10,14 @@
#endif
/* Struct definitions */
typedef struct _Telemetry {
typedef struct _EnvironmentalMeasurement {
float temperature;
float relative_humidity;
float barometric_pressure;
float gas_resistance;
float voltage;
float current;
} Telemetry;
} EnvironmentalMeasurement;
#ifdef __cplusplus
@@ -25,35 +25,35 @@ extern "C" {
#endif
/* Initializer values for message structs */
#define Telemetry_init_default {0, 0, 0, 0, 0, 0}
#define Telemetry_init_zero {0, 0, 0, 0, 0, 0}
#define EnvironmentalMeasurement_init_default {0, 0, 0, 0, 0, 0}
#define EnvironmentalMeasurement_init_zero {0, 0, 0, 0, 0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define Telemetry_temperature_tag 1
#define Telemetry_relative_humidity_tag 2
#define Telemetry_barometric_pressure_tag 3
#define Telemetry_gas_resistance_tag 4
#define Telemetry_voltage_tag 5
#define Telemetry_current_tag 6
#define EnvironmentalMeasurement_temperature_tag 1
#define EnvironmentalMeasurement_relative_humidity_tag 2
#define EnvironmentalMeasurement_barometric_pressure_tag 3
#define EnvironmentalMeasurement_gas_resistance_tag 4
#define EnvironmentalMeasurement_voltage_tag 5
#define EnvironmentalMeasurement_current_tag 6
/* Struct field encoding specification for nanopb */
#define Telemetry_FIELDLIST(X, a) \
#define EnvironmentalMeasurement_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, FLOAT, temperature, 1) \
X(a, STATIC, SINGULAR, FLOAT, relative_humidity, 2) \
X(a, STATIC, SINGULAR, FLOAT, barometric_pressure, 3) \
X(a, STATIC, SINGULAR, FLOAT, gas_resistance, 4) \
X(a, STATIC, SINGULAR, FLOAT, voltage, 5) \
X(a, STATIC, SINGULAR, FLOAT, current, 6)
#define Telemetry_CALLBACK NULL
#define Telemetry_DEFAULT NULL
#define EnvironmentalMeasurement_CALLBACK NULL
#define EnvironmentalMeasurement_DEFAULT NULL
extern const pb_msgdesc_t Telemetry_msg;
extern const pb_msgdesc_t EnvironmentalMeasurement_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define Telemetry_fields &Telemetry_msg
#define EnvironmentalMeasurement_fields &EnvironmentalMeasurement_msg
/* Maximum encoded size of messages (where known) */
#define Telemetry_size 30
#define EnvironmentalMeasurement_size 30
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -27,7 +27,7 @@ PB_BIND(MeshPacket, MeshPacket, 2)
PB_BIND(NodeInfo, NodeInfo, AUTO)
PB_BIND(MyNodeInfo, MyNodeInfo, AUTO)
PB_BIND(MyNodeInfo, MyNodeInfo, 2)
PB_BIND(LogRecord, LogRecord, AUTO)

View File

@@ -33,6 +33,8 @@ typedef enum _HardwareModel {
HardwareModel_ANDROID_SIM = 38,
HardwareModel_DIY_V1 = 39,
HardwareModel_RAK11200 = 40,
HardwareModel_NANO_G1 = 41,
HardwareModel_DR_DEV = 43,
HardwareModel_PRIVATE_HW = 255
} HardwareModel;
@@ -152,7 +154,9 @@ typedef struct _LogRecord {
typedef struct _MyNodeInfo {
uint32_t my_node_num;
bool has_gps;
uint32_t num_bands;
char region[12];
char hw_model_deprecated[16];
char firmware_version[18];
CriticalErrorCode error_code;
uint32_t error_address;
@@ -163,18 +167,12 @@ typedef struct _MyNodeInfo {
uint32_t min_app_version;
uint32_t max_channels;
pb_size_t air_period_tx_count;
uint32_t air_period_tx[8];
uint32_t air_period_tx[24];
pb_size_t air_period_rx_count;
uint32_t air_period_rx[8];
uint32_t air_period_rx[24];
bool has_wifi;
float channel_utilization;
float air_util_tx;
pb_size_t router_count;
uint32_t router[4];
pb_size_t router_snr_count;
float router_snr[4];
pb_size_t router_sec_count;
uint16_t router_sec[4];
} MyNodeInfo;
typedef struct _Position {
@@ -182,7 +180,6 @@ typedef struct _Position {
int32_t longitude_i;
int32_t altitude;
int32_t battery_level;
bool router_heartbeat;
uint32_t time;
Position_LocSource location_source;
Position_AltSource altitude_source;
@@ -337,26 +334,26 @@ extern "C" {
#endif
/* Initializer values for message structs */
#define Position_init_default {0, 0, 0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Position_init_default {0, 0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define User_init_default {"", "", "", {0}, _HardwareModel_MIN, 0, _Team_MIN, 0, 0, 0}
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define Routing_init_default {0, {RouteDiscovery_init_default}}
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
#define MyNodeInfo_init_default {0, 0, "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, {0, 0, 0, 0}, 0, {0, 0, 0, 0}, 0, {0, 0, 0, 0}}
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
#define ToRadio_init_default {0, {MeshPacket_init_default}}
#define ToRadio_PeerInfo_init_default {0, 0}
#define Position_init_zero {0, 0, 0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Position_init_zero {0, 0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define User_init_zero {"", "", "", {0}, _HardwareModel_MIN, 0, _Team_MIN, 0, 0, 0}
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
#define MyNodeInfo_init_zero {0, 0, "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, {0, 0, 0, 0}, 0, {0, 0, 0, 0}, 0, {0, 0, 0, 0}}
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
@@ -377,7 +374,9 @@ extern "C" {
#define LogRecord_level_tag 4
#define MyNodeInfo_my_node_num_tag 1
#define MyNodeInfo_has_gps_tag 2
#define MyNodeInfo_num_bands_tag 3
#define MyNodeInfo_region_tag 4
#define MyNodeInfo_hw_model_deprecated_tag 5
#define MyNodeInfo_firmware_version_tag 6
#define MyNodeInfo_error_code_tag 7
#define MyNodeInfo_error_address_tag 8
@@ -392,14 +391,10 @@ extern "C" {
#define MyNodeInfo_has_wifi_tag 18
#define MyNodeInfo_channel_utilization_tag 19
#define MyNodeInfo_air_util_tx_tag 20
#define MyNodeInfo_router_tag 21
#define MyNodeInfo_router_snr_tag 22
#define MyNodeInfo_router_sec_tag 23
#define Position_latitude_i_tag 1
#define Position_longitude_i_tag 2
#define Position_altitude_tag 3
#define Position_battery_level_tag 4
#define Position_router_heartbeat_tag 5
#define Position_time_tag 9
#define Position_location_source_tag 10
#define Position_altitude_source_tag 11
@@ -471,7 +466,6 @@ X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 1) \
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 2) \
X(a, STATIC, SINGULAR, INT32, altitude, 3) \
X(a, STATIC, SINGULAR, INT32, battery_level, 4) \
X(a, STATIC, SINGULAR, BOOL, router_heartbeat, 5) \
X(a, STATIC, SINGULAR, FIXED32, time, 9) \
X(a, STATIC, SINGULAR, UENUM, location_source, 10) \
X(a, STATIC, SINGULAR, UENUM, altitude_source, 11) \
@@ -566,7 +560,9 @@ X(a, STATIC, SINGULAR, FLOAT, snr, 7)
#define MyNodeInfo_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \
X(a, STATIC, SINGULAR, UINT32, num_bands, 3) \
X(a, STATIC, SINGULAR, STRING, region, 4) \
X(a, STATIC, SINGULAR, STRING, hw_model_deprecated, 5) \
X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \
X(a, STATIC, SINGULAR, UENUM, error_code, 7) \
X(a, STATIC, SINGULAR, UINT32, error_address, 8) \
@@ -580,10 +576,7 @@ X(a, STATIC, REPEATED, UINT32, air_period_tx, 16) \
X(a, STATIC, REPEATED, UINT32, air_period_rx, 17) \
X(a, STATIC, SINGULAR, BOOL, has_wifi, 18) \
X(a, STATIC, SINGULAR, FLOAT, channel_utilization, 19) \
X(a, STATIC, SINGULAR, FLOAT, air_util_tx, 20) \
X(a, STATIC, REPEATED, UINT32, router, 21) \
X(a, STATIC, REPEATED, FLOAT, router_snr, 22) \
X(a, STATIC, REPEATED, UINT32, router_sec, 23)
X(a, STATIC, SINGULAR, FLOAT, air_util_tx, 20)
#define MyNodeInfo_CALLBACK NULL
#define MyNodeInfo_DEFAULT NULL
@@ -654,16 +647,16 @@ extern const pb_msgdesc_t ToRadio_PeerInfo_msg;
#define ToRadio_PeerInfo_fields &ToRadio_PeerInfo_msg
/* Maximum encoded size of messages (where known) */
#define Position_size 155
#define Position_size 153
#define User_size 97
#define RouteDiscovery_size 40
#define Routing_size 42
#define Data_size 267
#define MeshPacket_size 318
#define NodeInfo_size 273
#define MyNodeInfo_size 282
#define NodeInfo_size 271
#define MyNodeInfo_size 457
#define LogRecord_size 81
#define FromRadio_size 327
#define FromRadio_size 466
#define ToRadio_size 321
#define ToRadio_PeerInfo_size 8

View File

@@ -23,7 +23,7 @@ typedef enum _PortNum {
PortNum_SERIAL_APP = 64,
PortNum_STORE_FORWARD_APP = 65,
PortNum_RANGE_TEST_APP = 66,
PortNum_TELEMETRY_APP = 67,
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67,
PortNum_ZPS_APP = 68,
PortNum_PRIVATE_APP = 256,
PortNum_ATAK_FORWARDER = 257,

View File

@@ -21,4 +21,3 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)

View File

@@ -14,24 +14,15 @@ typedef enum _RegionCode {
RegionCode_Unset = 0,
RegionCode_US = 1,
RegionCode_EU433 = 2,
RegionCode_EU868 = 3,
RegionCode_EU865 = 3,
RegionCode_CN = 4,
RegionCode_JP = 5,
RegionCode_ANZ = 6,
RegionCode_KR = 7,
RegionCode_TW = 8,
RegionCode_RU = 9,
RegionCode_IN = 10,
RegionCode_NZ865 = 11,
RegionCode_TH = 12
RegionCode_RU = 9
} RegionCode;
typedef enum _Role {
Role_Default = 0,
Role_Router = 1,
Role_Repeater = 2
} Role;
typedef enum _ChargeCurrent {
ChargeCurrent_MAUnset = 0,
ChargeCurrent_MA100 = 1,
@@ -99,17 +90,17 @@ typedef enum _InputEventChar {
InputEventChar_KEY_CANCEL = 24
} InputEventChar;
typedef enum _RadioConfig_UserPreferences_TelemetrySensorType {
RadioConfig_UserPreferences_TelemetrySensorType_DHT11 = 0,
RadioConfig_UserPreferences_TelemetrySensorType_DS18B20 = 1,
RadioConfig_UserPreferences_TelemetrySensorType_DHT12 = 2,
RadioConfig_UserPreferences_TelemetrySensorType_DHT21 = 3,
RadioConfig_UserPreferences_TelemetrySensorType_DHT22 = 4,
RadioConfig_UserPreferences_TelemetrySensorType_BME280 = 5,
RadioConfig_UserPreferences_TelemetrySensorType_BME680 = 6,
RadioConfig_UserPreferences_TelemetrySensorType_MCP9808 = 7,
RadioConfig_UserPreferences_TelemetrySensorType_SHTC3 = 8
} RadioConfig_UserPreferences_TelemetrySensorType;
typedef enum _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType {
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 = 0,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20 = 1,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT12 = 2,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT21 = 3,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT22 = 4,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME280 = 5,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME680 = 6,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MCP9808 = 7,
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_SHTC3 = 8
} RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType;
/* Struct definitions */
typedef struct _RadioConfig_UserPreferences {
@@ -129,7 +120,6 @@ typedef struct _RadioConfig_UserPreferences {
RegionCode region;
ChargeCurrent charge_current;
bool position_broadcast_smart;
Role role;
LocationSharing location_share;
GpsOperation gps_operation;
uint32_t gps_update_interval;
@@ -148,34 +138,34 @@ typedef struct _RadioConfig_UserPreferences {
bool debug_log_enabled;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
bool serialmodule_enabled;
bool serialmodule_echo;
uint32_t serialmodule_rxd;
uint32_t serialmodule_txd;
uint32_t serialmodule_timeout;
uint32_t serialmodule_mode;
bool ext_notification_module_enabled;
uint32_t ext_notification_module_output_ms;
uint32_t ext_notification_module_output;
bool ext_notification_module_active;
bool ext_notification_module_alert_message;
bool ext_notification_module_alert_bell;
bool range_test_module_enabled;
uint32_t range_test_module_sender;
bool range_test_module_save;
uint32_t store_forward_module_records;
uint32_t store_forward_module_history_return_max;
uint32_t store_forward_module_history_return_window;
bool telemetry_module_measurement_enabled;
bool telemetry_module_screen_enabled;
uint32_t telemetry_module_read_error_count_threshold;
uint32_t telemetry_module_update_interval;
uint32_t telemetry_module_recovery_interval;
bool telemetry_module_display_farenheit;
RadioConfig_UserPreferences_TelemetrySensorType telemetry_module_sensor_type;
uint32_t telemetry_module_sensor_pin;
bool store_forward_module_enabled;
bool store_forward_module_heartbeat;
bool serialplugin_enabled;
bool serialplugin_echo;
uint32_t serialplugin_rxd;
uint32_t serialplugin_txd;
uint32_t serialplugin_timeout;
uint32_t serialplugin_mode;
bool ext_notification_plugin_enabled;
uint32_t ext_notification_plugin_output_ms;
uint32_t ext_notification_plugin_output;
bool ext_notification_plugin_active;
bool ext_notification_plugin_alert_message;
bool ext_notification_plugin_alert_bell;
bool range_test_plugin_enabled;
uint32_t range_test_plugin_sender;
bool range_test_plugin_save;
uint32_t store_forward_plugin_records;
uint32_t store_forward_plugin_history_return_max;
uint32_t store_forward_plugin_history_return_window;
bool environmental_measurement_plugin_measurement_enabled;
bool environmental_measurement_plugin_screen_enabled;
uint32_t environmental_measurement_plugin_read_error_count_threshold;
uint32_t environmental_measurement_plugin_update_interval;
uint32_t environmental_measurement_plugin_recovery_interval;
bool environmental_measurement_plugin_display_farenheit;
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type;
uint32_t environmental_measurement_plugin_sensor_pin;
bool store_forward_plugin_enabled;
bool store_forward_plugin_heartbeat;
uint32_t position_flags;
bool is_always_powered;
uint32_t auto_screen_carousel_secs;
@@ -192,12 +182,12 @@ typedef struct _RadioConfig_UserPreferences {
InputEventChar rotary1_event_cw;
InputEventChar rotary1_event_ccw;
InputEventChar rotary1_event_press;
bool canned_message_module_enabled;
char canned_message_module_allow_input_source[16];
bool canned_message_module_send_bell;
bool canned_message_plugin_enabled;
char canned_message_plugin_allow_input_source[16];
char canned_message_plugin_messages[200];
bool canned_message_plugin_send_bell;
bool mqtt_encryption_enabled;
float adc_multiplier_override;
uint32_t serialmodule_baud;
} RadioConfig_UserPreferences;
typedef struct _RadioConfig {
@@ -208,12 +198,8 @@ typedef struct _RadioConfig {
/* Helper constants for enums */
#define _RegionCode_MIN RegionCode_Unset
#define _RegionCode_MAX RegionCode_TH
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TH+1))
#define _Role_MIN Role_Default
#define _Role_MAX Role_Repeater
#define _Role_ARRAYSIZE ((Role)(Role_Repeater+1))
#define _RegionCode_MAX RegionCode_RU
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_RU+1))
#define _ChargeCurrent_MIN ChargeCurrent_MAUnset
#define _ChargeCurrent_MAX ChargeCurrent_MA1320
@@ -239,9 +225,9 @@ typedef struct _RadioConfig {
#define _InputEventChar_MAX InputEventChar_KEY_BACK
#define _InputEventChar_ARRAYSIZE ((InputEventChar)(InputEventChar_KEY_BACK+1))
#define _RadioConfig_UserPreferences_TelemetrySensorType_MIN RadioConfig_UserPreferences_TelemetrySensorType_DHT11
#define _RadioConfig_UserPreferences_TelemetrySensorType_MAX RadioConfig_UserPreferences_TelemetrySensorType_SHTC3
#define _RadioConfig_UserPreferences_TelemetrySensorType_ARRAYSIZE ((RadioConfig_UserPreferences_TelemetrySensorType)(RadioConfig_UserPreferences_TelemetrySensorType_SHTC3+1))
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_SHTC3
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_SHTC3+1))
#ifdef __cplusplus
@@ -250,9 +236,9 @@ extern "C" {
/* Initializer values for message structs */
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _Role_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_TelemetrySensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, "", 0, 0, 0, 0}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, "", "", 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _Role_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_TelemetrySensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, "", 0, 0, 0, 0}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, "", "", 0, 0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
@@ -271,7 +257,6 @@ extern "C" {
#define RadioConfig_UserPreferences_region_tag 15
#define RadioConfig_UserPreferences_charge_current_tag 16
#define RadioConfig_UserPreferences_position_broadcast_smart_tag 17
#define RadioConfig_UserPreferences_role_tag 18
#define RadioConfig_UserPreferences_location_share_tag 32
#define RadioConfig_UserPreferences_gps_operation_tag 33
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
@@ -289,34 +274,34 @@ extern "C" {
#define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
#define RadioConfig_UserPreferences_serialmodule_enabled_tag 120
#define RadioConfig_UserPreferences_serialmodule_echo_tag 121
#define RadioConfig_UserPreferences_serialmodule_rxd_tag 122
#define RadioConfig_UserPreferences_serialmodule_txd_tag 123
#define RadioConfig_UserPreferences_serialmodule_timeout_tag 124
#define RadioConfig_UserPreferences_serialmodule_mode_tag 125
#define RadioConfig_UserPreferences_ext_notification_module_enabled_tag 126
#define RadioConfig_UserPreferences_ext_notification_module_output_ms_tag 127
#define RadioConfig_UserPreferences_ext_notification_module_output_tag 128
#define RadioConfig_UserPreferences_ext_notification_module_active_tag 129
#define RadioConfig_UserPreferences_ext_notification_module_alert_message_tag 130
#define RadioConfig_UserPreferences_ext_notification_module_alert_bell_tag 131
#define RadioConfig_UserPreferences_range_test_module_enabled_tag 132
#define RadioConfig_UserPreferences_range_test_module_sender_tag 133
#define RadioConfig_UserPreferences_range_test_module_save_tag 134
#define RadioConfig_UserPreferences_store_forward_module_records_tag 137
#define RadioConfig_UserPreferences_store_forward_module_history_return_max_tag 138
#define RadioConfig_UserPreferences_store_forward_module_history_return_window_tag 139
#define RadioConfig_UserPreferences_telemetry_module_measurement_enabled_tag 140
#define RadioConfig_UserPreferences_telemetry_module_screen_enabled_tag 141
#define RadioConfig_UserPreferences_telemetry_module_read_error_count_threshold_tag 142
#define RadioConfig_UserPreferences_telemetry_module_update_interval_tag 143
#define RadioConfig_UserPreferences_telemetry_module_recovery_interval_tag 144
#define RadioConfig_UserPreferences_telemetry_module_display_farenheit_tag 145
#define RadioConfig_UserPreferences_telemetry_module_sensor_type_tag 146
#define RadioConfig_UserPreferences_telemetry_module_sensor_pin_tag 147
#define RadioConfig_UserPreferences_store_forward_module_enabled_tag 148
#define RadioConfig_UserPreferences_store_forward_module_heartbeat_tag 149
#define RadioConfig_UserPreferences_serialplugin_enabled_tag 120
#define RadioConfig_UserPreferences_serialplugin_echo_tag 121
#define RadioConfig_UserPreferences_serialplugin_rxd_tag 122
#define RadioConfig_UserPreferences_serialplugin_txd_tag 123
#define RadioConfig_UserPreferences_serialplugin_timeout_tag 124
#define RadioConfig_UserPreferences_serialplugin_mode_tag 125
#define RadioConfig_UserPreferences_ext_notification_plugin_enabled_tag 126
#define RadioConfig_UserPreferences_ext_notification_plugin_output_ms_tag 127
#define RadioConfig_UserPreferences_ext_notification_plugin_output_tag 128
#define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129
#define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130
#define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131
#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132
#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
#define RadioConfig_UserPreferences_store_forward_plugin_history_return_max_tag 138
#define RadioConfig_UserPreferences_store_forward_plugin_history_return_window_tag 139
#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140
#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141
#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142
#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143
#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144
#define RadioConfig_UserPreferences_environmental_measurement_plugin_display_farenheit_tag 145
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 148
#define RadioConfig_UserPreferences_store_forward_plugin_heartbeat_tag 149
#define RadioConfig_UserPreferences_position_flags_tag 150
#define RadioConfig_UserPreferences_is_always_powered_tag 151
#define RadioConfig_UserPreferences_auto_screen_carousel_secs_tag 152
@@ -333,12 +318,12 @@ extern "C" {
#define RadioConfig_UserPreferences_rotary1_event_cw_tag 164
#define RadioConfig_UserPreferences_rotary1_event_ccw_tag 165
#define RadioConfig_UserPreferences_rotary1_event_press_tag 166
#define RadioConfig_UserPreferences_canned_message_module_enabled_tag 170
#define RadioConfig_UserPreferences_canned_message_module_allow_input_source_tag 171
#define RadioConfig_UserPreferences_canned_message_module_send_bell_tag 173
#define RadioConfig_UserPreferences_canned_message_plugin_enabled_tag 170
#define RadioConfig_UserPreferences_canned_message_plugin_allow_input_source_tag 171
#define RadioConfig_UserPreferences_canned_message_plugin_messages_tag 172
#define RadioConfig_UserPreferences_canned_message_plugin_send_bell_tag 173
#define RadioConfig_UserPreferences_mqtt_encryption_enabled_tag 174
#define RadioConfig_UserPreferences_adc_multiplier_override_tag 175
#define RadioConfig_UserPreferences_serialmodule_baud_tag 176
#define RadioConfig_preferences_tag 1
/* Struct field encoding specification for nanopb */
@@ -365,7 +350,6 @@ X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, SINGULAR, UENUM, region, 15) \
X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \
X(a, STATIC, SINGULAR, BOOL, position_broadcast_smart, 17) \
X(a, STATIC, SINGULAR, UENUM, role, 18) \
X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
@@ -383,34 +367,34 @@ X(a, STATIC, SINGULAR, UINT32, gps_max_dop, 46) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
X(a, STATIC, SINGULAR, BOOL, serialmodule_enabled, 120) \
X(a, STATIC, SINGULAR, BOOL, serialmodule_echo, 121) \
X(a, STATIC, SINGULAR, UINT32, serialmodule_rxd, 122) \
X(a, STATIC, SINGULAR, UINT32, serialmodule_txd, 123) \
X(a, STATIC, SINGULAR, UINT32, serialmodule_timeout, 124) \
X(a, STATIC, SINGULAR, UINT32, serialmodule_mode, 125) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_module_enabled, 126) \
X(a, STATIC, SINGULAR, UINT32, ext_notification_module_output_ms, 127) \
X(a, STATIC, SINGULAR, UINT32, ext_notification_module_output, 128) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_module_active, 129) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_module_alert_message, 130) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_module_alert_bell, 131) \
X(a, STATIC, SINGULAR, BOOL, range_test_module_enabled, 132) \
X(a, STATIC, SINGULAR, UINT32, range_test_module_sender, 133) \
X(a, STATIC, SINGULAR, BOOL, range_test_module_save, 134) \
X(a, STATIC, SINGULAR, UINT32, store_forward_module_records, 137) \
X(a, STATIC, SINGULAR, UINT32, store_forward_module_history_return_max, 138) \
X(a, STATIC, SINGULAR, UINT32, store_forward_module_history_return_window, 139) \
X(a, STATIC, SINGULAR, BOOL, telemetry_module_measurement_enabled, 140) \
X(a, STATIC, SINGULAR, BOOL, telemetry_module_screen_enabled, 141) \
X(a, STATIC, SINGULAR, UINT32, telemetry_module_read_error_count_threshold, 142) \
X(a, STATIC, SINGULAR, UINT32, telemetry_module_update_interval, 143) \
X(a, STATIC, SINGULAR, UINT32, telemetry_module_recovery_interval, 144) \
X(a, STATIC, SINGULAR, BOOL, telemetry_module_display_farenheit, 145) \
X(a, STATIC, SINGULAR, UENUM, telemetry_module_sensor_type, 146) \
X(a, STATIC, SINGULAR, UINT32, telemetry_module_sensor_pin, 147) \
X(a, STATIC, SINGULAR, BOOL, store_forward_module_enabled, 148) \
X(a, STATIC, SINGULAR, BOOL, store_forward_module_heartbeat, 149) \
X(a, STATIC, SINGULAR, BOOL, serialplugin_enabled, 120) \
X(a, STATIC, SINGULAR, BOOL, serialplugin_echo, 121) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_rxd, 122) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_txd, 123) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_mode, 125) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_enabled, 126) \
X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \
X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_history_return_max, 138) \
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_history_return_window, 139) \
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) \
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \
X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147) \
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 148) \
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_heartbeat, 149) \
X(a, STATIC, SINGULAR, UINT32, position_flags, 150) \
X(a, STATIC, SINGULAR, BOOL, is_always_powered, 151) \
X(a, STATIC, SINGULAR, UINT32, auto_screen_carousel_secs, 152) \
@@ -427,12 +411,12 @@ X(a, STATIC, SINGULAR, UINT32, rotary1_pin_press, 163) \
X(a, STATIC, SINGULAR, UENUM, rotary1_event_cw, 164) \
X(a, STATIC, SINGULAR, UENUM, rotary1_event_ccw, 165) \
X(a, STATIC, SINGULAR, UENUM, rotary1_event_press, 166) \
X(a, STATIC, SINGULAR, BOOL, canned_message_module_enabled, 170) \
X(a, STATIC, SINGULAR, STRING, canned_message_module_allow_input_source, 171) \
X(a, STATIC, SINGULAR, BOOL, canned_message_module_send_bell, 173) \
X(a, STATIC, SINGULAR, BOOL, canned_message_plugin_enabled, 170) \
X(a, STATIC, SINGULAR, STRING, canned_message_plugin_allow_input_source, 171) \
X(a, STATIC, SINGULAR, STRING, canned_message_plugin_messages, 172) \
X(a, STATIC, SINGULAR, BOOL, canned_message_plugin_send_bell, 173) \
X(a, STATIC, SINGULAR, BOOL, mqtt_encryption_enabled, 174) \
X(a, STATIC, SINGULAR, FLOAT, adc_multiplier_override, 175) \
X(a, STATIC, SINGULAR, UINT32, serialmodule_baud, 176)
X(a, STATIC, SINGULAR, FLOAT, adc_multiplier_override, 175)
#define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL
@@ -444,8 +428,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
/* Maximum encoded size of messages (where known) */
#define RadioConfig_size 608
#define RadioConfig_UserPreferences_size 605
#define RadioConfig_size 801
#define RadioConfig_UserPreferences_size 798
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -11,7 +11,7 @@
#include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp>
#include <HTTPURLEncodedBodyParser.hpp>
#include <FSCommon.h>
#include <SPIFFS.h>
#ifndef NO_ESP32
#include "esp_task_wdt.h"
@@ -46,10 +46,7 @@ using namespace httpsserver;
#include <WiFiClientSecure.h>
HTTPClient httpClient;
// needed for ESP32-targz
#define DEST_FS_USES_LITTLEFS
#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
#define ESP_ARDUINO_VERSION ESP_ARDUINO_VERSION_VAL(1, 0, 4)
#define DEST_FS_USES_SPIFFS
#include <ESP32-targz.h>
// We need to specify some content-type mapping, so the resources get delivered with the
@@ -130,9 +127,9 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
ResourceNode *nodeAdmin = new ResourceNode("/admin", "GET", &handleAdmin);
ResourceNode *nodeAdminSettings = new ResourceNode("/admin/settings", "GET", &handleAdminSettings);
ResourceNode *nodeAdminSettingsApply = new ResourceNode("/admin/settings/apply", "POST", &handleAdminSettingsApply);
ResourceNode *nodeAdminFs = new ResourceNode("/admin/fs", "GET", &handleFs);
ResourceNode *nodeUpdateFs = new ResourceNode("/admin/fs/update", "POST", &handleUpdateFs);
ResourceNode *nodeDeleteFs = new ResourceNode("/admin/fs/delete", "GET", &handleDeleteFsContent);
ResourceNode *nodeAdminSPIFFS = new ResourceNode("/admin/spiffs", "GET", &handleSPIFFS);
ResourceNode *nodeUpdateSPIFFS = new ResourceNode("/admin/spiffs/update", "POST", &handleUpdateSPIFFS);
ResourceNode *nodeDeleteSPIFFS = new ResourceNode("/admin/spiffs/delete", "GET", &handleDeleteSPIFFSContent);
ResourceNode *nodeRestart = new ResourceNode("/restart", "POST", &handleRestart);
ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
@@ -140,8 +137,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks);
ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED);
ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport);
ResourceNode *nodeJsonFsBrowseStatic = new ResourceNode("/json/fs/browse/static", "GET", &handleFsBrowseStatic);
ResourceNode *nodeJsonDelete = new ResourceNode("/json/fs/delete/static", "DELETE", &handleFsDeleteStatic);
ResourceNode *nodeJsonSpiffsBrowseStatic = new ResourceNode("/json/spiffs/browse/static", "GET", &handleSpiffsBrowseStatic);
ResourceNode *nodeJsonDelete = new ResourceNode("/json/spiffs/delete/static", "DELETE", &handleSpiffsDeleteStatic);
ResourceNode *nodeRoot = new ResourceNode("/*", "GET", &handleStatic);
@@ -156,13 +153,13 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
secureServer->registerNode(nodeFormUpload);
secureServer->registerNode(nodeJsonScanNetworks);
secureServer->registerNode(nodeJsonBlinkLED);
secureServer->registerNode(nodeJsonFsBrowseStatic);
secureServer->registerNode(nodeJsonSpiffsBrowseStatic);
secureServer->registerNode(nodeJsonDelete);
secureServer->registerNode(nodeJsonReport);
secureServer->registerNode(nodeUpdateFs);
secureServer->registerNode(nodeDeleteFs);
secureServer->registerNode(nodeUpdateSPIFFS);
secureServer->registerNode(nodeDeleteSPIFFS);
secureServer->registerNode(nodeAdmin);
secureServer->registerNode(nodeAdminFs);
secureServer->registerNode(nodeAdminSPIFFS);
secureServer->registerNode(nodeAdminSettings);
secureServer->registerNode(nodeAdminSettingsApply);
secureServer->registerNode(nodeRoot); // This has to be last
@@ -177,13 +174,13 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
insecureServer->registerNode(nodeFormUpload);
insecureServer->registerNode(nodeJsonScanNetworks);
insecureServer->registerNode(nodeJsonBlinkLED);
insecureServer->registerNode(nodeJsonFsBrowseStatic);
insecureServer->registerNode(nodeJsonSpiffsBrowseStatic);
insecureServer->registerNode(nodeJsonDelete);
insecureServer->registerNode(nodeJsonReport);
insecureServer->registerNode(nodeUpdateFs);
insecureServer->registerNode(nodeDeleteFs);
insecureServer->registerNode(nodeUpdateSPIFFS);
insecureServer->registerNode(nodeDeleteSPIFFS);
insecureServer->registerNode(nodeAdmin);
insecureServer->registerNode(nodeAdminFs);
insecureServer->registerNode(nodeAdminSPIFFS);
insecureServer->registerNode(nodeAdminSettings);
insecureServer->registerNode(nodeAdminSettingsApply);
insecureServer->registerNode(nodeRoot); // This has to be last
@@ -272,14 +269,14 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
DEBUG_MSG("webAPI handleAPIv1ToRadio\n");
}
void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "application/json");
res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET");
File root = FSCom.open("/");
File root = SPIFFS.open("/");
if (root.isDirectory()) {
res->println("{");
@@ -316,9 +313,9 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
}
res->print("],");
res->print("\"filesystem\" : {");
res->print("\"total\" : " + String(FSCom.totalBytes()) + ",");
res->print("\"used\" : " + String(FSCom.usedBytes()) + ",");
res->print("\"free\" : " + String(FSCom.totalBytes() - FSCom.usedBytes()));
res->print("\"total\" : " + String(SPIFFS.totalBytes()) + ",");
res->print("\"used\" : " + String(SPIFFS.usedBytes()) + ",");
res->print("\"free\" : " + String(SPIFFS.totalBytes() - SPIFFS.usedBytes()));
res->println("}");
res->println("},");
res->println("\"status\": \"ok\"");
@@ -326,7 +323,7 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
}
}
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
{
ResourceParameters *params = req->getParams();
std::string paramValDelete;
@@ -336,7 +333,7 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
res->setHeader("Access-Control-Allow-Methods", "DELETE");
if (params->getQueryParameter("delete", paramValDelete)) {
std::string pathDelete = "/" + paramValDelete;
if (FSCom.remove(pathDelete.c_str())) {
if (SPIFFS.remove(pathDelete.c_str())) {
Serial.println(pathDelete.c_str());
res->println("{");
res->println("\"status\": \"ok\"");
@@ -364,18 +361,18 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
std::string filename = "/static/" + parameter1;
std::string filenameGzip = "/static/" + parameter1 + ".gz";
// Try to open the file
// Try to open the file from SPIFFS
File file;
bool has_set_content_type = false;
if (FSCom.exists(filename.c_str())) {
file = FSCom.open(filename.c_str());
if (SPIFFS.exists(filename.c_str())) {
file = SPIFFS.open(filename.c_str());
if (!file.available()) {
DEBUG_MSG("File not available - %s\n", filename.c_str());
}
} else if (FSCom.exists(filenameGzip.c_str())) {
file = FSCom.open(filenameGzip.c_str());
} else if (SPIFFS.exists(filenameGzip.c_str())) {
file = SPIFFS.open(filenameGzip.c_str());
res->setHeader("Content-Encoding", "gzip");
if (!file.available()) {
DEBUG_MSG("File not available - %s\n", filenameGzip.c_str());
@@ -383,16 +380,13 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
} else {
has_set_content_type = true;
filenameGzip = "/static/index.html.gz";
file = FSCom.open(filenameGzip.c_str());
file = SPIFFS.open(filenameGzip.c_str());
res->setHeader("Content-Type", "text/html");
if (!file.available()) {
DEBUG_MSG("File not available - %s\n", filenameGzip.c_str());
res->println("Web server is running.<br><br>The content you are looking for can't be found. Please see: <a "
"href=https://meshtastic.org/docs/getting-started/faq#wifi--web-browser>FAQ</a>.<br><br><a "
"href=/admin>admin</a>");
return;
} else {
res->setHeader("Content-Encoding", "gzip");
}
@@ -416,7 +410,7 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
res->setHeader("Content-Type", "application/octet-stream");
}
// Read the file and write it to the HTTP response body
// Read the file from SPIFFS and write it to the HTTP response body
size_t length = 0;
do {
char buffer[256];
@@ -430,7 +424,6 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
return;
} else {
DEBUG_MSG("ERROR: This should not have happened...\n");
res->println("ERROR: This should not have happened...");
}
}
@@ -509,12 +502,20 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
return;
}
// SPIFFS limits the total lenth of a path + file to 31 characters.
if (filename.length() + 8 > 31) {
DEBUG_MSG("Uploaded filename too long!\n");
res->println("<p>Uploaded filename too long! Limit of 23 characters.</p>");
delete parser;
return;
}
// You should check file name validity and all that, but we skip that to make the core
// concepts of the body parser functionality easier to understand.
std::string pathname = "/static/" + filename;
// Create a new file to stream the data into
File file = FSCom.open(pathname.c_str(), "w");
// Create a new file on spiffs to stream the data into
File file = SPIFFS.open(pathname.c_str(), "w");
size_t fileLength = 0;
didwrite = true;
@@ -528,7 +529,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
// DEBUG_MSG("\n\nreadLength - %i\n", readLength);
// Abort the transfer if there is less than 50k space left on the filesystem.
if (FSCom.totalBytes() - FSCom.usedBytes() < 51200) {
if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < 51200) {
file.close();
res->println("<p>Write aborted! Reserving 50k on filesystem.</p>");
@@ -648,9 +649,9 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
res->printf("\"heap_free\": %d,\n", ESP.getFreeHeap());
res->printf("\"psram_total\": %d,\n", ESP.getPsramSize());
res->printf("\"psram_free\": %d,\n", ESP.getFreePsram());
res->println("\"fs_total\" : " + String(FSCom.totalBytes()) + ",");
res->println("\"fs_used\" : " + String(FSCom.usedBytes()) + ",");
res->println("\"fs_free\" : " + String(FSCom.totalBytes() - FSCom.usedBytes()));
res->println("\"spiffs_total\" : " + String(SPIFFS.totalBytes()) + ",");
res->println("\"spiffs_used\" : " + String(SPIFFS.usedBytes()) + ",");
res->println("\"spiffs_free\" : " + String(SPIFFS.totalBytes() - SPIFFS.usedBytes()));
res->println("},");
res->println("\"power\": {");
@@ -698,7 +699,7 @@ void handleHotspot(HTTPRequest *req, HTTPResponse *res)
res->println("<meta http-equiv=\"refresh\" content=\"0;url=/\" />\n");
}
void handleUpdateFs(HTTPRequest *req, HTTPResponse *res)
void handleUpdateSPIFFS(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "text/html");
res->setHeader("Access-Control-Allow-Origin", "*");
@@ -715,7 +716,7 @@ void handleUpdateFs(HTTPRequest *req, HTTPResponse *res)
if (streamptr != nullptr) {
DEBUG_MSG("Connection to content server ... success!\n");
File root = FSCom.open("/");
File root = SPIFFS.open("/");
File file = root.openNextFile();
DEBUG_MSG("Deleting files from /static : \n");
@@ -724,7 +725,7 @@ void handleUpdateFs(HTTPRequest *req, HTTPResponse *res)
String filePath = String(file.name());
if (filePath.indexOf("/static") == 0) {
DEBUG_MSG(" %s\n", file.name());
FSCom.remove(file.name());
SPIFFS.remove(file.name());
}
file = root.openNextFile();
}
@@ -751,10 +752,10 @@ void handleUpdateFs(HTTPRequest *req, HTTPResponse *res)
res->printf("Stream size %d<br><br>\n", streamSize);
}
if (!TARUnpacker->tarStreamExpander(streamptr, streamSize, FSCom, "/static")) {
if (!TARUnpacker->tarStreamExpander(streamptr, streamSize, SPIFFS, "/static")) {
res->printf("tarStreamExpander failed with return code #%d\n", TARUnpacker->tarGzGetError());
Serial.printf("tarStreamExpander failed with return code #%d\n", TARUnpacker->tarGzGetError());
client->stop();
return;
} else {
/*
@@ -772,6 +773,7 @@ void handleUpdateFs(HTTPRequest *req, HTTPResponse *res)
} else {
res->printf("Failed to establish http connection\n");
Serial.println("Failed to establish http connection");
client->stop();
return;
}
@@ -785,16 +787,16 @@ void handleUpdateFs(HTTPRequest *req, HTTPResponse *res)
webServerThread->requestRestart = (millis() / 1000) + 5;
}
void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res)
void handleDeleteSPIFFSContent(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "text/html");
res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET");
res->println("<h1>Meshtastic</h1>\n");
res->println("Deleting Content in /static/*");
res->println("Deleting SPIFFS Content in /static/*");
File root = FSCom.open("/");
File root = SPIFFS.open("/");
File file = root.openNextFile();
DEBUG_MSG("Deleting files from /static : \n");
@@ -803,7 +805,7 @@ void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res)
String filePath = String(file.name());
if (filePath.indexOf("/static") == 0) {
DEBUG_MSG(" %s\n", file.name());
FSCom.remove(file.name());
SPIFFS.remove(file.name());
}
file = root.openNextFile();
}
@@ -818,7 +820,7 @@ void handleAdmin(HTTPRequest *req, HTTPResponse *res)
res->println("<h1>Meshtastic</h1>\n");
res->println("<a href=/admin/settings>Settings</a><br>\n");
res->println("<a href=/admin/fs>Manage Web Content</a><br>\n");
res->println("<a href=/admin/spiffs>Manage Web Content</a><br>\n");
res->println("<a href=/json/report>Device Report</a><br>\n");
}
@@ -858,14 +860,14 @@ void handleAdminSettingsApply(HTTPRequest *req, HTTPResponse *res)
}
void handleFs(HTTPRequest *req, HTTPResponse *res)
void handleSPIFFS(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "text/html");
res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET");
res->println("<h1>Meshtastic</h1>\n");
res->println("<a href=/admin/fs/delete>Delete Web Content</a><p><form action=/admin/fs/update "
res->println("<a href=/admin/spiffs/delete>Delete Web Content</a><p><form action=/admin/spiffs/update "
"method=post><input type=submit value=UPDATE_WEB_CONTENT></form>Be patient!");
res->println("<p><hr><p><a href=/admin>Back to admin</a>\n");
}

View File

@@ -11,13 +11,13 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res);
void handleRestart(HTTPRequest *req, HTTPResponse *res);
void handleFormUpload(HTTPRequest *req, HTTPResponse *res);
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res);
void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res);
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res);
void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res);
void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res);
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res);
void handleReport(HTTPRequest *req, HTTPResponse *res);
void handleUpdateFs(HTTPRequest *req, HTTPResponse *res);
void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res);
void handleFs(HTTPRequest *req, HTTPResponse *res);
void handleUpdateSPIFFS(HTTPRequest *req, HTTPResponse *res);
void handleDeleteSPIFFSContent(HTTPRequest *req, HTTPResponse *res);
void handleSPIFFS(HTTPRequest *req, HTTPResponse *res);
void handleAdmin(HTTPRequest *req, HTTPResponse *res);
void handleAdminSettings(HTTPRequest *req, HTTPResponse *res);
void handleAdminSettingsApply(HTTPRequest *req, HTTPResponse *res);
@@ -34,7 +34,9 @@ class HttpAPI : public PhoneAPI
// Nothing here yet
protected:
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override { return true; } // FIXME, be smarter about this
};

View File

@@ -175,9 +175,6 @@ bool initWifi(bool forceSoftAP)
{
forcedSoftAP = forceSoftAP;
// strcpy(radioConfig.preferences.wifi_ssid, "meshtastic");
// strcpy(radioConfig.preferences.wifi_password, "meshtastic!");
if ((radioConfig.has_preferences && radioConfig.preferences.wifi_ssid[0]) || forceSoftAP) {
const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password;

View File

@@ -1,11 +1,16 @@
#include "mesh-pb-constants.h"
#include "FSCommon.h"
#include "FS.h"
#include "configuration.h"
#include <Arduino.h>
#include <assert.h>
#include <pb_decode.h>
#include <pb_encode.h>
#ifdef ARDUINO_ARCH_NRF52
#include "Adafruit_LittleFS.h"
using namespace Adafruit_LittleFS_Namespace; // To get File type
#endif
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
/// returns the encoded packet size
size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc_t *fields, const void *src_struct)
@@ -67,4 +72,4 @@ bool is_in_helper(uint32_t n, const uint32_t *array, pb_size_t count)
return true;
return false;
}
}

View File

@@ -1,538 +0,0 @@
#include "configuration.h"
#include "CannedMessageModule.h"
#include "MeshService.h"
#include "FSCommon.h"
#include "mesh/generated/cannedmessages.pb.h"
// TODO: reuse defined from Screen.cpp
#define FONT_SMALL ArialMT_Plain_10
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
// Remove Canned message screen if no action is taken for some milliseconds
#define INACTIVATE_AFTER_MS 20000
static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto";
CannedMessageModuleConfig cannedMessageModuleConfig;
CannedMessageModule *cannedMessageModule;
// TODO: move it into NodeDB.h!
extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
extern bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct);
CannedMessageModule::CannedMessageModule()
: SinglePortPlugin("canned", PortNum_TEXT_MESSAGE_APP),
concurrency::OSThread("CannedMessageModule")
{
if (radioConfig.preferences.canned_message_module_enabled)
{
this->loadProtoForModule();
if(this->splitConfiguredMessages() <= 0)
{
DEBUG_MSG("CannedMessageModule: No messages are configured. Module is disabled\n");
this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
}
else
{
DEBUG_MSG("CannedMessageModule is enabled\n");
this->inputObserver.observe(inputBroker);
}
}
}
/**
* @brief Items in array this->messages will be set to be pointing on the right
* starting points of the string this->messageStore
*
* @return int Returns the number of messages found.
*/
int CannedMessageModule::splitConfiguredMessages()
{
int messageIndex = 0;
int i = 0;
// collect all the message parts
strcpy(
this->messageStore,
cannedMessageModuleConfig.messagesPart1);
strcat(
this->messageStore,
cannedMessageModuleConfig.messagesPart2);
strcat(
this->messageStore,
cannedMessageModuleConfig.messagesPart3);
strcat(
this->messageStore,
cannedMessageModuleConfig.messagesPart4);
// The first message points to the beginning of the store.
this->messages[messageIndex++] =
this->messageStore;
int upTo =
strlen(this->messageStore) - 1;
while (i < upTo)
{
if (this->messageStore[i] == '|')
{
// Message ending found, replace it with string-end character.
this->messageStore[i] = '\0';
DEBUG_MSG("CannedMessage %d is: '%s'\n",
messageIndex-1, this->messages[messageIndex-1]);
// hit our max messages, bail
if (messageIndex >= CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT)
{
this->messagesCount = messageIndex;
return this->messagesCount;
}
// Next message starts after pipe (|) just found.
this->messages[messageIndex++] =
(this->messageStore + i + 1);
}
i += 1;
}
if (strlen(this->messages[messageIndex-1]) > 0)
{
// We have a last message.
DEBUG_MSG("CannedMessage %d is: '%s'\n",
messageIndex-1, this->messages[messageIndex-1]);
this->messagesCount = messageIndex;
}
else
{
this->messagesCount = messageIndex-1;
}
return this->messagesCount;
}
int CannedMessageModule::handleInputEvent(const InputEvent *event)
{
if (
(strlen(radioConfig.preferences.canned_message_module_allow_input_source) > 0) &&
(strcmp(radioConfig.preferences.canned_message_module_allow_input_source, event->source) != 0) &&
(strcmp(radioConfig.preferences.canned_message_module_allow_input_source, "_any") != 0))
{
// Event source is not accepted.
// Event only accepted if source matches the configured one, or
// the configured one is "_any" (or if there is no configured
// source at all)
return 0;
}
bool validEvent = false;
if (event->inputEvent == static_cast<char>(InputEventChar_KEY_UP))
{
DEBUG_MSG("Canned message event UP\n");
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP;
validEvent = true;
}
if (event->inputEvent == static_cast<char>(InputEventChar_KEY_DOWN))
{
DEBUG_MSG("Canned message event DOWN\n");
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN;
validEvent = true;
}
if (event->inputEvent == static_cast<char>(InputEventChar_KEY_SELECT))
{
DEBUG_MSG("Canned message event Select\n");
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
validEvent = true;
}
if (validEvent)
{
// Let runOnce to be called immediately.
setIntervalFromNow(0);
}
return 0;
}
void CannedMessageModule::sendText(NodeNum dest,
const char* message,
bool wantReplies)
{
MeshPacket *p = allocDataPacket();
p->to = dest;
p->want_ack = true;
p->decoded.payload.size = strlen(message);
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
if (radioConfig.preferences.canned_message_module_send_bell)
{
p->decoded.payload.bytes[p->decoded.payload.size-1] = 7; // Bell character
p->decoded.payload.bytes[p->decoded.payload.size] = '\0'; // Bell character
p->decoded.payload.size++;
}
DEBUG_MSG("Sending message id=%d, msg=%.*s\n",
p->id, p->decoded.payload.size, p->decoded.payload.bytes);
service.sendToMesh(p);
}
int32_t CannedMessageModule::runOnce()
{
if ((!radioConfig.preferences.canned_message_module_enabled)
|| (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)
|| (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE))
{
return 30000; // TODO: should return MAX_VAL
}
DEBUG_MSG("Check status\n");
UIFrameEvent e = {false, true};
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE)
{
// TODO: might have some feedback of sendig state
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
e.frameChanged = true;
this->currentMessageIndex = -1;
this->notifyObservers(&e);
}
else if (
(this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE)
&& (millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)
{
// Reset module
DEBUG_MSG("Reset due the lack of activity.\n");
e.frameChanged = true;
this->currentMessageIndex = -1;
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
this->notifyObservers(&e);
}
else if (this->currentMessageIndex == -1)
{
this->currentMessageIndex = 0;
DEBUG_MSG("First touch (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
e.frameChanged = true;
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
}
else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT)
{
sendText(
NODENUM_BROADCAST,
this->messages[this->currentMessageIndex],
true);
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
this->currentMessageIndex = -1;
this->notifyObservers(&e);
return 2000;
}
else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP)
{
this->currentMessageIndex = getPrevIndex();
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
DEBUG_MSG("MOVE UP (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
}
else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_DOWN)
{
this->currentMessageIndex = this->getNextIndex();
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
DEBUG_MSG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
}
if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE)
{
this->lastTouchMillis = millis();
this->notifyObservers(&e);
return INACTIVATE_AFTER_MS;
}
return 30000; // TODO: should return MAX_VAL
}
const char* CannedMessageModule::getCurrentMessage()
{
return this->messages[this->currentMessageIndex];
}
const char* CannedMessageModule::getPrevMessage()
{
return this->messages[this->getPrevIndex()];
}
const char* CannedMessageModule::getNextMessage()
{
return this->messages[this->getNextIndex()];
}
bool CannedMessageModule::shouldDraw()
{
if (!radioConfig.preferences.canned_message_module_enabled)
{
return false;
}
return (currentMessageIndex != -1) || (this->runState != CANNED_MESSAGE_RUN_STATE_INACTIVE);
}
int CannedMessageModule::getNextIndex()
{
if (this->currentMessageIndex >= (this->messagesCount -1))
{
return 0;
}
else
{
return this->currentMessageIndex + 1;
}
}
int CannedMessageModule::getPrevIndex()
{
if (this->currentMessageIndex <= 0)
{
return this->messagesCount - 1;
}
else
{
return this->currentMessageIndex - 1;
}
}
void CannedMessageModule::drawFrame(
OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
displayedNodeNum = 0; // Not currently showing a node pane
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(display->getWidth()/2 + x, 0 + y + 12, "Sending...");
}
else
{
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
display->drawString(0 + x, 0 + y, cannedMessageModule->getPrevMessage());
display->setFont(FONT_MEDIUM);
display->drawString(0 + x, 0 + y + 8, cannedMessageModule->getCurrentMessage());
display->setFont(FONT_SMALL);
display->drawString(0 + x, 0 + y + 24, cannedMessageModule->getNextMessage());
}
}
void CannedMessageModule::loadProtoForModule()
{
if (!loadProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(cannedMessagesConfigFile), CannedMessageModuleConfig_fields, &cannedMessageModuleConfig)) {
installDefaultCannedMessageModuleConfig();
}
}
/**
* @brief Save the module config to file.
*
* @return true On success.
* @return false On error.
*/
bool CannedMessageModule::saveProtoForModule()
{
bool okay = true;
#ifdef FS
FS.mkdir("/prefs");
#endif
okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(CannedMessageModuleConfig), CannedMessageModuleConfig_fields, &cannedMessageModuleConfig);
return okay;
}
/**
* @brief Fill configuration with default values.
*/
void CannedMessageModule::installDefaultCannedMessageModuleConfig()
{
memset(cannedMessageModuleConfig.messagesPart1, 0, sizeof(cannedMessageModuleConfig.messagesPart1));
memset(cannedMessageModuleConfig.messagesPart2, 0, sizeof(cannedMessageModuleConfig.messagesPart2));
memset(cannedMessageModuleConfig.messagesPart3, 0, sizeof(cannedMessageModuleConfig.messagesPart3));
memset(cannedMessageModuleConfig.messagesPart4, 0, sizeof(cannedMessageModuleConfig.messagesPart4));
}
/**
* @brief An admin message arrived to AdminModule. We are asked whether we want to handle that.
*
* @param mp The mesh packet arrived.
* @param request The AdminMessage request extracted from the packet.
* @param response The prepared response
* @return AdminMessageHandleResult HANDLED if message was handled
* HANDLED_WITH_RESULT if a result is also prepared.
*/
AdminMessageHandleResult CannedMessageModule::handleAdminMessageForModule(
const MeshPacket &mp, AdminMessage *request, AdminMessage *response)
{
AdminMessageHandleResult result;
switch (request->which_variant) {
case AdminMessage_get_canned_message_module_part1_request_tag:
DEBUG_MSG("Client is getting radio canned message part1\n");
this->handleGetCannedMessageModulePart1(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_get_canned_message_module_part2_request_tag:
DEBUG_MSG("Client is getting radio canned message part2\n");
this->handleGetCannedMessageModulePart2(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_get_canned_message_module_part3_request_tag:
DEBUG_MSG("Client is getting radio canned message part3\n");
this->handleGetCannedMessageModulePart3(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_get_canned_message_module_part4_request_tag:
DEBUG_MSG("Client is getting radio canned message part4\n");
this->handleGetCannedMessageModulePart4(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_set_canned_message_module_part1_tag:
DEBUG_MSG("Client is setting radio canned message part 1\n");
this->handleSetCannedMessageModulePart1(
request->set_canned_message_module_part1);
result = AdminMessageHandleResult::HANDLED;
break;
case AdminMessage_set_canned_message_module_part2_tag:
DEBUG_MSG("Client is setting radio canned message part 2\n");
this->handleSetCannedMessageModulePart2(
request->set_canned_message_module_part2);
result = AdminMessageHandleResult::HANDLED;
break;
case AdminMessage_set_canned_message_module_part3_tag:
DEBUG_MSG("Client is setting radio canned message part 3\n");
this->handleSetCannedMessageModulePart3(
request->set_canned_message_module_part3);
result = AdminMessageHandleResult::HANDLED;
break;
case AdminMessage_set_canned_message_module_part4_tag:
DEBUG_MSG("Client is setting radio canned message part 4\n");
this->handleSetCannedMessageModulePart4(
request->set_canned_message_module_part4);
result = AdminMessageHandleResult::HANDLED;
break;
default:
result = AdminMessageHandleResult::NOT_HANDLED;
}
return result;
}
void CannedMessageModule::handleGetCannedMessageModulePart1(
const MeshPacket &req, AdminMessage *response)
{
DEBUG_MSG("*** handleGetCannedMessageModulePart1\n");
assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part1_response_tag;
strcpy(
response->get_canned_message_module_part1_response,
cannedMessageModuleConfig.messagesPart1);
}
void CannedMessageModule::handleGetCannedMessageModulePart2(
const MeshPacket &req, AdminMessage *response)
{
DEBUG_MSG("*** handleGetCannedMessageModulePart2\n");
assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part2_response_tag;
strcpy(
response->get_canned_message_module_part2_response,
cannedMessageModuleConfig.messagesPart2);
}
void CannedMessageModule::handleGetCannedMessageModulePart3(
const MeshPacket &req, AdminMessage *response)
{
DEBUG_MSG("*** handleGetCannedMessageModulePart3\n");
assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part3_response_tag;
strcpy(
response->get_canned_message_module_part3_response,
cannedMessageModuleConfig.messagesPart3);
}
void CannedMessageModule::handleGetCannedMessageModulePart4(
const MeshPacket &req, AdminMessage *response)
{
DEBUG_MSG("*** handleGetCannedMessageModulePart4\n");
assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part4_response_tag;
strcpy(
response->get_canned_message_module_part4_response,
cannedMessageModuleConfig.messagesPart4);
}
void CannedMessageModule::handleSetCannedMessageModulePart1(const char *from_msg)
{
int changed = 0;
if (*from_msg)
{
changed |= strcmp(cannedMessageModuleConfig.messagesPart1, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart1, from_msg);
DEBUG_MSG("*** from_msg.text:%s\n", from_msg);
}
if (changed)
{
this->saveProtoForModule();
}
}
void CannedMessageModule::handleSetCannedMessageModulePart2(const char *from_msg)
{
int changed = 0;
if (*from_msg)
{
changed |= strcmp(cannedMessageModuleConfig.messagesPart2, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart2, from_msg);
}
if (changed)
{
this->saveProtoForModule();
}
}
void CannedMessageModule::handleSetCannedMessageModulePart3(const char *from_msg)
{
int changed = 0;
if (*from_msg)
{
changed |= strcmp(cannedMessageModuleConfig.messagesPart3, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart3, from_msg);
}
if (changed)
{
this->saveProtoForModule();
}
}
void CannedMessageModule::handleSetCannedMessageModulePart4(const char *from_msg)
{
int changed = 0;
if (*from_msg)
{
changed |= strcmp(cannedMessageModuleConfig.messagesPart4, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart4, from_msg);
}
if (changed)
{
this->saveProtoForModule();
}
}

View File

@@ -1,86 +0,0 @@
#pragma once
#include "ProtobufPlugin.h"
#include "input/InputBroker.h"
enum cannedMessageModuleRunState
{
CANNED_MESSAGE_RUN_STATE_DISABLED,
CANNED_MESSAGE_RUN_STATE_INACTIVE,
CANNED_MESSAGE_RUN_STATE_ACTIVE,
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
CANNED_MESSAGE_RUN_STATE_ACTION_UP,
CANNED_MESSAGE_RUN_STATE_ACTION_DOWN,
};
#define CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT 50
/**
* Sum of CannedMessageModuleConfig part sizes.
*/
#define CANNED_MESSAGE_MODULE_MESSAGES_SIZE 800
class CannedMessageModule :
public SinglePortPlugin,
public Observable<const UIFrameEvent *>,
private concurrency::OSThread
{
CallbackObserver<CannedMessageModule, const InputEvent *> inputObserver =
CallbackObserver<CannedMessageModule, const InputEvent *>(
this, &CannedMessageModule::handleInputEvent);
public:
CannedMessageModule();
const char* getCurrentMessage();
const char* getPrevMessage();
const char* getNextMessage();
bool shouldDraw();
void eventUp();
void eventDown();
void eventSelect();
void handleGetCannedMessageModulePart1(const MeshPacket &req, AdminMessage *response);
void handleGetCannedMessageModulePart2(const MeshPacket &req, AdminMessage *response);
void handleGetCannedMessageModulePart3(const MeshPacket &req, AdminMessage *response);
void handleGetCannedMessageModulePart4(const MeshPacket &req, AdminMessage *response);
void handleSetCannedMessageModulePart1(const char *from_msg);
void handleSetCannedMessageModulePart2(const char *from_msg);
void handleSetCannedMessageModulePart3(const char *from_msg);
void handleSetCannedMessageModulePart4(const char *from_msg);
protected:
virtual int32_t runOnce() override;
void sendText(
NodeNum dest,
const char* message,
bool wantReplies);
int splitConfiguredMessages();
int getNextIndex();
int getPrevIndex();
int handleInputEvent(const InputEvent *event);
virtual bool wantUIFrame() override { return this->shouldDraw(); }
virtual Observable<const UIFrameEvent *>* getUIFrameObservable() override { return this; }
virtual void drawFrame(
OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
virtual AdminMessageHandleResult handleAdminMessageForModule(
const MeshPacket &mp, AdminMessage *request, AdminMessage *response) override;
void loadProtoForModule();
bool saveProtoForModule();
void installDefaultCannedMessageModuleConfig();
int currentMessageIndex = -1;
cannedMessageModuleRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE+1];
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
int messagesCount = 0;
unsigned long lastTouchMillis = 0;
};
extern CannedMessageModule *cannedMessageModule;

View File

@@ -1,187 +0,0 @@
#include "configuration.h"
#include "ExternalNotificationModule.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
#include "Router.h"
#include <Arduino.h>
//#include <assert.h>
/*
Documentation:
https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/modules/ExternalNotificationModule.md
This module supports:
https://github.com/meshtastic/Meshtastic-device/issues/654
Quick reference:
radioConfig.preferences.ext_notification_module_enabled
0 = Disabled (Default)
1 = Enabled
radioConfig.preferences.ext_notification_module_active
0 = Active Low (Default)
1 = Active High
radioConfig.preferences.ext_notification_module_alert_message
0 = Disabled (Default)
1 = Alert when a text message comes
radioConfig.preferences.ext_notification_module_alert_bell
0 = Disabled (Default)
1 = Alert when the bell character is received
radioConfig.preferences.ext_notification_module_output
GPIO of the output. (Default = 13)
radioConfig.preferences.ext_notification_module_output_ms
Amount of time in ms for the alert. Default is 1000.
*/
// Default configurations
#define EXT_NOTIFICATION_MODULE_OUTPUT EXT_NOTIFY_OUT
#define EXT_NOTIFICATION_MODULE_OUTPUT_MS 1000
#define ASCII_BELL 0x07
bool externalCurrentState = 0;
uint32_t externalTurnedOn = 0;
int32_t ExternalNotificationModule::runOnce()
{
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// radioConfig.preferences.ext_notification_module_enabled = 1;
// radioConfig.preferences.ext_notification_module_alert_message = 1;
// radioConfig.preferences.ext_notification_module_active = 1;
// radioConfig.preferences.ext_notification_module_alert_bell = 1;
// radioConfig.preferences.ext_notification_module_output_ms = 1000;
// radioConfig.preferences.ext_notification_module_output = 13;
if (externalCurrentState) {
// If the output is turned on, turn it back off after the given period of time.
if (externalTurnedOn + (radioConfig.preferences.ext_notification_module_output_ms
? radioConfig.preferences.ext_notification_module_output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
DEBUG_MSG("Turning off external notification\n");
setExternalOff();
}
}
return (25);
}
void ExternalNotificationModule::setExternalOn()
{
#ifdef EXT_NOTIFY_OUT
externalCurrentState = 1;
externalTurnedOn = millis();
digitalWrite((radioConfig.preferences.ext_notification_module_output ? radioConfig.preferences.ext_notification_module_output
: EXT_NOTIFICATION_MODULE_OUTPUT),
(radioConfig.preferences.ext_notification_module_active ? true : false));
#endif
}
void ExternalNotificationModule::setExternalOff()
{
#ifdef EXT_NOTIFY_OUT
externalCurrentState = 0;
digitalWrite((radioConfig.preferences.ext_notification_module_output ? radioConfig.preferences.ext_notification_module_output
: EXT_NOTIFICATION_MODULE_OUTPUT),
(radioConfig.preferences.ext_notification_module_active ? false : true));
#endif
}
// --------
ExternalNotificationModule::ExternalNotificationModule()
: SinglePortPlugin("ExternalNotificationModule", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread(
"ExternalNotificationModule")
{
// restrict to the admin channel for rx
boundChannel = Channels::gpioChannel;
#ifndef NO_ESP32
#ifdef EXT_NOTIFY_OUT
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// radioConfig.preferences.ext_notification_module_enabled = 1;
// radioConfig.preferences.ext_notification_module_alert_message = 1;
// radioConfig.preferences.ext_notification_module_active = 1;
// radioConfig.preferences.ext_notification_module_alert_bell = 1;
// radioConfig.preferences.ext_notification_module_output_ms = 1000;
// radioConfig.preferences.ext_notification_module_output = 13;
if (radioConfig.preferences.ext_notification_module_enabled) {
DEBUG_MSG("Initializing External Notification Module\n");
// Set the direction of a pin
pinMode((radioConfig.preferences.ext_notification_module_output ? radioConfig.preferences.ext_notification_module_output
: EXT_NOTIFICATION_MODULE_OUTPUT),
OUTPUT);
// Turn off the pin
setExternalOff();
} else {
DEBUG_MSG("External Notification Module Disabled\n");
enabled = false;
}
#endif
#endif
}
ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
{
#ifndef NO_ESP32
#ifdef EXT_NOTIFY_OUT
if (radioConfig.preferences.ext_notification_module_enabled) {
if (getFrom(&mp) != nodeDB.getNodeNum()) {
// TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
// Need to know if and how this could be a problem.
if (radioConfig.preferences.ext_notification_module_alert_bell) {
auto &p = mp.decoded;
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
for (int i = 0; i < p.payload.size; i++) {
if (p.payload.bytes[i] == ASCII_BELL) {
setExternalOn();
}
}
}
if (radioConfig.preferences.ext_notification_module_alert_message) {
DEBUG_MSG("externalNotificationModule - Notification Module\n");
setExternalOn();
}
}
} else {
DEBUG_MSG("External Notification Module Disabled\n");
}
#endif
#endif
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
}

View File

@@ -1,60 +0,0 @@
#include "configuration.h"
#include "input/InputBroker.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "modules/AdminModule.h"
#include "modules/CannedMessageModule.h"
#include "modules/ExternalNotificationModule.h"
#include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h"
#include "modules/RemoteHardwareModule.h"
#include "modules/ReplyModule.h"
#include "modules/RoutingModule.h"
#include "modules/TextMessageModule.h"
#ifndef PORTDUINO
#include "modules/Telemetry/Telemetry.h"
#endif
#ifndef NO_ESP32
#include "modules/esp32/RangeTestModule.h"
#include "modules/esp32/SerialModule.h"
#include "modules/esp32/StoreForwardModule.h"
#endif
/**
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
*/
void setupModules()
{
inputBroker = new InputBroker();
adminModule = new AdminModule();
nodeInfoModule = new NodeInfoModule();
positionModule = new PositionModule();
textMessageModule = new TextMessageModule();
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable.
new RemoteHardwareModule();
new ReplyModule();
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
rotaryEncoderInterruptImpl1->init();
cannedMessageModule = new CannedMessageModule();
#ifndef PORTDUINO
new TelemetryModule();
#endif
#ifndef NO_ESP32
// Only run on an esp32 based device.
/*
Maintained by MC Hamster (Jm Casler) jm@casler.org
*/
new SerialModule();
new ExternalNotificationModule();
storeForwardModule = new StoreForwardModule();
new RangeTestModule();
#endif
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra acks
routingModule = new RoutingModule();
}

View File

@@ -1,6 +0,0 @@
#pragma once
/**
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
*/
void setupModules();

View File

@@ -1,15 +0,0 @@
#include "../mesh/generated/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_BME280.h>
#define BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class BME280Sensor : virtual public TelemetrySensor {
private:
Adafruit_BME280 bme280;
public:
BME280Sensor();
virtual int32_t runOnce() override;
virtual bool getMeasurement(Telemetry *measurement) override;
};

View File

@@ -1,15 +0,0 @@
#include "../mesh/generated/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_BME680.h>
#define BME_680_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class BME680Sensor : virtual public TelemetrySensor {
private:
Adafruit_BME680 bme680;
public:
BME680Sensor();
virtual int32_t runOnce() override;
virtual bool getMeasurement(Telemetry *measurement) override;
};

View File

@@ -1,36 +0,0 @@
#include "../mesh/generated/telemetry.pb.h"
#include "configuration.h"
#include "MeshService.h"
#include "TelemetrySensor.h"
#include "DHTSensor.h"
#include <DHT.h>
DHTSensor::DHTSensor() : TelemetrySensor {} {
}
int32_t DHTSensor::runOnce() {
if (RadioConfig_UserPreferences_TelemetrySensorType_DHT11 ||
RadioConfig_UserPreferences_TelemetrySensorType_DHT12) {
dht = new DHT(radioConfig.preferences.telemetry_module_sensor_pin, DHT11);
}
else {
dht = new DHT(radioConfig.preferences.telemetry_module_sensor_pin, DHT22);
}
dht->begin();
dht->read();
DEBUG_MSG("Telemetry: Opened DHT11/DHT12 on pin: %d\n",
radioConfig.preferences.telemetry_module_sensor_pin);
return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
}
bool DHTSensor::getMeasurement(Telemetry *measurement) {
if (!dht->read(true)) {
DEBUG_MSG("Telemetry: FAILED TO READ DATA\n");
return false;
}
measurement->relative_humidity = dht->readHumidity();
measurement->temperature = dht->readTemperature();
return true;
}

View File

@@ -1,15 +0,0 @@
#include "../mesh/generated/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <DHT.h>
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class DHTSensor : virtual public TelemetrySensor {
private:
DHT *dht = NULL;
public:
DHTSensor();
virtual int32_t runOnce() override;
virtual bool getMeasurement(Telemetry *measurement) override;
};

View File

@@ -1,17 +0,0 @@
#include "../mesh/generated/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <DS18B20.h>
#include <OneWire.h>
#define DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class DallasSensor : virtual public TelemetrySensor {
private:
OneWire *oneWire = NULL;
DS18B20 *ds18b20 = NULL;
public:
DallasSensor();
virtual int32_t runOnce() override;
virtual bool getMeasurement(Telemetry *measurement) override;
};

View File

@@ -1,15 +0,0 @@
#include "../mesh/generated/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_MCP9808.h>
#define MCP_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class MCP9808Sensor : virtual public TelemetrySensor {
private:
Adafruit_MCP9808 mcp9808;
public:
MCP9808Sensor();
virtual int32_t runOnce() override;
virtual bool getMeasurement(Telemetry *measurement) override;
};

View File

@@ -1,12 +0,0 @@
#pragma once
#include "../mesh/generated/telemetry.pb.h"
#define DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class TelemetrySensor {
protected:
TelemetrySensor() { }
public:
virtual int32_t runOnce() = 0;
virtual bool getMeasurement(Telemetry *measurement) = 0;
};

View File

@@ -1,299 +0,0 @@
#include "Telemetry.h"
#include "../mesh/generated/telemetry.pb.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
#include "Router.h"
#include "configuration.h"
#include "main.h"
#include <OLEDDisplay.h>
#include <OLEDDisplayUi.h>
// Sensors
#include "Sensor/BME280Sensor.h"
#include "Sensor/BME680Sensor.h"
#include "Sensor/DHTSensor.h"
#include "Sensor/DallasSensor.h"
#include "Sensor/MCP9808Sensor.h"
BME280Sensor bme280Sensor;
BME680Sensor bme680Sensor;
DHTSensor dhtSensor;
DallasSensor dallasSensor;
MCP9808Sensor mcp9808Sensor;
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
#ifdef HAS_EINK
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24
#else
#define FONT_SMALL ArialMT_Plain_10
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
#define fontHeight(font) ((font)[1] + 1) // height is position 1
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
int32_t TelemetryModule::runOnce()
{
#ifndef PORTDUINO
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
/*
radioConfig.preferences.telemetry_module_measurement_enabled = 1;
radioConfig.preferences.telemetry_module_screen_enabled = 1;
radioConfig.preferences.telemetry_module_read_error_count_threshold = 5;
radioConfig.preferences.telemetry_module_update_interval = 600;
radioConfig.preferences.telemetry_module_recovery_interval = 60;
radioConfig.preferences.telemetry_module_display_farenheit = false;
radioConfig.preferences.telemetry_module_sensor_pin = 13;
radioConfig.preferences.telemetry_module_sensor_type =
RadioConfig_UserPreferences_TelemetrySensorType::
RadioConfig_UserPreferences_TelemetrySensorType_BME280;
*/
if (!(radioConfig.preferences.telemetry_module_measurement_enabled ||
radioConfig.preferences.telemetry_module_screen_enabled)) {
// If this module is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
return (INT32_MAX);
}
if (firstTime) {
// This is the first time the OSThread library has called this function, so do some setup
firstTime = 0;
if (radioConfig.preferences.telemetry_module_measurement_enabled) {
DEBUG_MSG("Telemetry: Initializing\n");
// it's possible to have this module enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
switch (radioConfig.preferences.telemetry_module_sensor_type) {
case RadioConfig_UserPreferences_TelemetrySensorType_DHT11:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT12:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT21:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT22:
return dhtSensor.runOnce();
case RadioConfig_UserPreferences_TelemetrySensorType_DS18B20:
return dallasSensor.runOnce();
case RadioConfig_UserPreferences_TelemetrySensorType_BME280:
return bme280Sensor.runOnce();
case RadioConfig_UserPreferences_TelemetrySensorType_BME680:
return bme680Sensor.runOnce();
case RadioConfig_UserPreferences_TelemetrySensorType_MCP9808:
return mcp9808Sensor.runOnce();
default:
DEBUG_MSG("Telemetry: Invalid sensor type selected; Disabling module");
return (INT32_MAX);
break;
}
}
return (INT32_MAX);
} else {
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
if (!radioConfig.preferences.telemetry_module_measurement_enabled)
return (INT32_MAX);
// this is not the first time OSThread library has called this function
// so just do what we intend to do on the interval
if (sensor_read_error_count > radioConfig.preferences.telemetry_module_read_error_count_threshold) {
if (radioConfig.preferences.telemetry_module_recovery_interval > 0) {
DEBUG_MSG("Telemetry: TEMPORARILY DISABLED; The "
"telemetry_module_read_error_count_threshold has been exceed: %d. Will retry reads in "
"%d seconds\n",
radioConfig.preferences.telemetry_module_read_error_count_threshold,
radioConfig.preferences.telemetry_module_recovery_interval);
sensor_read_error_count = 0;
return (radioConfig.preferences.telemetry_module_recovery_interval * 1000);
}
DEBUG_MSG("Telemetry: DISABLED; The telemetry_module_read_error_count_threshold has "
"been exceed: %d. Reads will not be retried until after device reset\n",
radioConfig.preferences.telemetry_module_read_error_count_threshold);
return (INT32_MAX);
} else if (sensor_read_error_count > 0) {
DEBUG_MSG("Telemetry: There have been %d sensor read failures. Will retry %d more times\n",
sensor_read_error_count, sensor_read_error_count, sensor_read_error_count,
radioConfig.preferences.telemetry_module_read_error_count_threshold -
sensor_read_error_count);
}
if (!sendOurTelemetry()) {
// if we failed to read the sensor, then try again
// as soon as we can according to the maximum polling frequency
switch (radioConfig.preferences.telemetry_module_sensor_type) {
case RadioConfig_UserPreferences_TelemetrySensorType_DHT11:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT12:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT21:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT22:
return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
case RadioConfig_UserPreferences_TelemetrySensorType_DS18B20:
return (DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
case RadioConfig_UserPreferences_TelemetrySensorType_BME280:
case RadioConfig_UserPreferences_TelemetrySensorType_BME680:
return (BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
case RadioConfig_UserPreferences_TelemetrySensorType_MCP9808:
return (MCP_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
default:
return (DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
}
}
}
// The return of runOnce is an int32 representing the desired number of
// miliseconds until the function should be called again by the
// OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds
return (radioConfig.preferences.telemetry_module_update_interval * 1000);
#endif
}
bool TelemetryModule::wantUIFrame()
{
return radioConfig.preferences.telemetry_module_screen_enabled;
}
String GetSenderName(const MeshPacket &mp)
{
String sender;
auto node = nodeDB.getNode(getFrom(&mp));
if (node) {
sender = node->user.short_name;
} else {
sender = "UNK";
}
return sender;
}
uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp)
{
uint32_t now = getTime();
uint32_t last_seen = mp->rx_time;
int delta = (int)(now - last_seen);
if (delta < 0) // our clock must be slightly off still - not set from GPS yet
delta = 0;
return delta;
}
float TelemetryModule::CelsiusToFarenheit(float c)
{
return (c * 9) / 5 + 32;
}
void TelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_MEDIUM);
display->drawString(x, y, "Environment");
if (lastMeasurementPacket == nullptr) {
display->setFont(FONT_SMALL);
display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement");
return;
}
Telemetry lastMeasurement;
uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket);
String lastSender = GetSenderName(*lastMeasurementPacket);
auto &p = lastMeasurementPacket->decoded;
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, Telemetry_fields, &lastMeasurement)) {
display->setFont(FONT_SMALL);
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
DEBUG_MSG("Telemetry: unable to decode last packet");
return;
}
display->setFont(FONT_SMALL);
String last_temp = String(lastMeasurement.temperature, 0) + "°C";
if (radioConfig.preferences.telemetry_module_display_farenheit) {
last_temp = String(CelsiusToFarenheit(lastMeasurement.temperature), 0) + "°F";
}
display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + lastSender + "(" + String(agoSecs) + "s)");
display->drawString(x, y += fontHeight(FONT_SMALL) - 2,"Temp/Hum: " + last_temp + " / " + String(lastMeasurement.relative_humidity, 0) + "%");
if (lastMeasurement.barometric_pressure != 0)
display->drawString(x, y += fontHeight(FONT_SMALL),"Press: " + String(lastMeasurement.barometric_pressure, 0) + "hPA");
}
bool TelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemetry *p)
{
if (!(radioConfig.preferences.telemetry_module_measurement_enabled ||
radioConfig.preferences.telemetry_module_screen_enabled)) {
// If this module is not enabled in any capacity, don't handle the packet, and allow other modules to consume
return false;
}
String sender = GetSenderName(mp);
DEBUG_MSG("Telemetry: Received data from %s\n", sender);
DEBUG_MSG("Telemetry->relative_humidity: %f\n", p->relative_humidity);
DEBUG_MSG("Telemetry->temperature: %f\n", p->temperature);
DEBUG_MSG("Telemetry->barometric_pressure: %f\n", p->barometric_pressure);
DEBUG_MSG("Telemetry->gas_resistance: %f\n", p->gas_resistance);
lastMeasurementPacket = packetPool.allocCopy(mp);
return false; // Let others look at this message also if they want
}
bool TelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies)
{
Telemetry m;
m.barometric_pressure = 0;
m.gas_resistance = 0;
DEBUG_MSG("-----------------------------------------\n");
DEBUG_MSG("Telemetry: Read data\n");
switch (radioConfig.preferences.telemetry_module_sensor_type) {
case RadioConfig_UserPreferences_TelemetrySensorType_DS18B20:
if (!dallasSensor.getMeasurement(&m))
sensor_read_error_count++;
break;
case RadioConfig_UserPreferences_TelemetrySensorType_DHT11:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT12:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT21:
case RadioConfig_UserPreferences_TelemetrySensorType_DHT22:
if (!dhtSensor.getMeasurement(&m))
sensor_read_error_count++;
break;
case RadioConfig_UserPreferences_TelemetrySensorType_BME280:
bme280Sensor.getMeasurement(&m);
break;
case RadioConfig_UserPreferences_TelemetrySensorType_BME680:
bme680Sensor.getMeasurement(&m);
break;
case RadioConfig_UserPreferences_TelemetrySensorType_MCP9808:
mcp9808Sensor.getMeasurement(&m);
break;
default:
DEBUG_MSG("Telemetry: Invalid sensor type selected; Disabling module");
return false;
}
DEBUG_MSG("Telemetry->relative_humidity: %f\n", m.relative_humidity);
DEBUG_MSG("Telemetry->temperature: %f\n", m.temperature);
DEBUG_MSG("Telemetry->barometric_pressure: %f\n", m.barometric_pressure);
DEBUG_MSG("Telemetry->gas_resistance: %f\n", m.gas_resistance);
sensor_read_error_count = 0;
MeshPacket *p = allocDataProtobuf(m);
p->to = dest;
p->decoded.want_response = wantReplies;
lastMeasurementPacket = packetPool.allocCopy(*p);
DEBUG_MSG("Telemetry: Sending packet to mesh");
service.sendToMesh(p);
return true;
}

3
src/nrf52/FS.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
// FIXME - make a FS abstraction for NRF52

View File

@@ -32,8 +32,8 @@ void __attribute__((noreturn)) __assert_func(const char *file, int line, const c
{
DEBUG_MSG("assert failed %s: %d, %s, test=%s\n", file, line, func, failedexpr);
// debugger_break(); FIXME doesn't work, possibly not for segger
while (1)
; // FIXME, reboot!
// Reboot cpu
NVIC_SystemReset();
}
void getMacAddr(uint8_t *dmac)
@@ -193,4 +193,4 @@ void clearBonds() {
nrf52Bluetooth->setup();
}
nrf52Bluetooth->clearBonds();
}
}

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "AdminModule.h"
#include "AdminPlugin.h"
#include "Channels.h"
#include "MeshService.h"
#include "NodeDB.h"
@@ -10,7 +10,7 @@
#include "unistd.h"
#endif
AdminModule *adminModule;
AdminPlugin *adminPlugin;
/// A special reserved string to indicate strings we can not share with external nodes. We will use this 'reserved' word instead.
/// Also, to make setting work correctly, if someone tries to set a string to this reserved value we assume they don't really want a change.
@@ -30,7 +30,7 @@ static void writeSecret(char *buf, const char *currentVal) {
}
}
void AdminModule::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
{
if (req.decoded.want_response) {
// We create the reply here
@@ -41,7 +41,7 @@ void AdminModule::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
}
}
void AdminModule::handleGetRadio(const MeshPacket &req)
void AdminPlugin::handleGetRadio(const MeshPacket &req)
{
if (req.decoded.want_response) {
// We create the reply here
@@ -61,11 +61,8 @@ void AdminModule::handleGetRadio(const MeshPacket &req)
}
}
bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
{
// if handled == false, then let others look at this message also if they want
bool handled = false;
assert(r);
switch (r->which_variant) {
case AdminMessage_set_owner_tag:
@@ -122,28 +119,14 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
#endif
default:
AdminMessage response = AdminMessage_init_default;
AdminMessageHandleResult handleResult = MeshPlugin::handleAdminMessageForAllPlugins(mp, r, &response);
if (handleResult == AdminMessageHandleResult::HANDLED_WITH_RESPONSE)
{
myReply = allocDataProtobuf(response);
}
else if (mp.decoded.want_response)
{
DEBUG_MSG("We did not responded to a request that wanted a respond. req.variant=%d\n", r->which_variant);
}
else if (handleResult != AdminMessageHandleResult::HANDLED)
{
// Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages
DEBUG_MSG("Ignoring nonrelevant admin %d\n", r->which_variant);
}
// Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages
DEBUG_MSG("Ignoring nonrelevant admin %d\n", r->which_variant);
break;
}
return handled;
return false; // Let others look at this message also if they want
}
void AdminModule::handleSetOwner(const User &o)
void AdminPlugin::handleSetOwner(const User &o)
{
int changed = 0;
@@ -173,7 +156,7 @@ void AdminModule::handleSetOwner(const User &o)
service.reloadOwner();
}
void AdminModule::handleSetChannel(const Channel &cc)
void AdminPlugin::handleSetChannel(const Channel &cc)
{
channels.setChannel(cc);
@@ -187,7 +170,7 @@ void AdminModule::handleSetChannel(const Channel &cc)
}
}
void AdminModule::handleSetRadio(RadioConfig &r)
void AdminPlugin::handleSetRadio(RadioConfig &r)
{
writeSecret(r.preferences.wifi_password, radioConfig.preferences.wifi_password);
radioConfig = r;
@@ -195,7 +178,7 @@ void AdminModule::handleSetRadio(RadioConfig &r)
service.reloadConfig();
}
AdminModule::AdminModule() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
{
// restrict to the admin channel for rx
boundChannel = Channels::adminChannel;

Some files were not shown because too many files have changed in this diff Show More