mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-22 10:42:49 +00:00
Merge branch 'master' of https://github.com/meshtastic/Meshtastic-device
This commit is contained in:
76
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
Normal file
76
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
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
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
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
39
.github/actions/initbuild/action.yml
vendored
@@ -1,39 +0,0 @@
|
||||
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
|
||||
|
||||
|
||||
2
.github/workflows/main_matrix.yml
vendored
2
.github/workflows/main_matrix.yml
vendored
@@ -37,6 +37,7 @@ jobs:
|
||||
- board: meshtastic-diy-v1
|
||||
- board: rak4631_5005
|
||||
- board: rak4631_19003
|
||||
- board: rak4631_5005_eink
|
||||
- board: t-echo
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
@@ -162,6 +163,7 @@ jobs:
|
||||
include:
|
||||
- board: rak4631_5005
|
||||
- board: rak4631_19003
|
||||
- board: rak4631_5005_eink
|
||||
- board: t-echo
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -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
|
||||
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
|
||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -4,5 +4,8 @@
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide",
|
||||
"xaver.clang-format"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
|
||||
72
README-docker.md
Normal file
72
README-docker.md
Normal file
@@ -0,0 +1,72 @@
|
||||
## 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
|
||||
|
||||
@@ -7,8 +7,12 @@
|
||||
|
||||
Update Instructions
|
||||
|
||||
[Using Meshtastic Flasher](https://meshtastic.org/docs/getting-started/meshtastic-flasher)
|
||||
|
||||
Manual Method
|
||||
|
||||
[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 doccumentation](https://meshtastic.org/docs/developers)
|
||||
For developer information and specific building instructions, please see the [developer documentation](https://meshtastic.org/docs/developers)
|
||||
|
||||
@@ -9,7 +9,7 @@ BOARDS_ESP32="rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-
|
||||
#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_19003 t-echo"
|
||||
BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo"
|
||||
#BOARDS_NRF52=""
|
||||
|
||||
OUTDIR=release/latest
|
||||
|
||||
@@ -8,6 +8,10 @@ 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 littlefs-python")
|
||||
|
||||
Import("projenv")
|
||||
|
||||
|
||||
17
docker.txt
17
docker.txt
@@ -1,17 +0,0 @@
|
||||
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>
|
||||
|
||||
@@ -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 plugins
|
||||
* DONE cleanup the external notification and serial modules
|
||||
* 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 RouterPlugin for *all* packets - not just Router packets
|
||||
* DONE call RouterModule 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 plugin (move settings ops out of PhoneAPI)
|
||||
* DONE enable remote setttings access by moving settings operations into a regular module (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 plugin operation
|
||||
* DONE implement 'get channels' Admin module 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 plugin LAST and drop ACK if someone else has already replied)
|
||||
* 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 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 plugins (and restrict routing plugin to the "control" channel)
|
||||
* DONE add channel restrictions for modules (and restrict routing module 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 plugins for messages inbound from the phone (or generated locally)
|
||||
* DONE confirm we are still calling the modules 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 plugin (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
|
||||
* have phoneapi done via module (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 plugins
|
||||
* DONE move want_replies handling into modules
|
||||
* 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 plugin
|
||||
* DONE Add SinglePortNumPlugin - as the new most useful baseclass
|
||||
* DONE fix position sending to use new module
|
||||
* DONE Add SinglePortNumModule - 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
|
||||
|
||||
@@ -23,8 +23,9 @@ default_envs = tbeam
|
||||
;default_envs = t-echo
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = rak4631
|
||||
;default_envs = rak4630
|
||||
;default_envs = rak4631_5005
|
||||
;default_envs = rak4631_5005_eink
|
||||
;default_envs = rak4631_19003
|
||||
;default_envs = meshtastic-diy-v1
|
||||
;default_envs = meshtastic-diy-v1.1
|
||||
|
||||
@@ -195,7 +196,7 @@ build_flags =
|
||||
-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/> -<plugins/esp32> -<mqtt/>
|
||||
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
; monitor_port = /dev/ttyACM1
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 2930129e8e...f6ba3722be
220
src/ButtonThread.h
Normal file
220
src/ButtonThread.h
Normal file
@@ -0,0 +1,220 @@
|
||||
#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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
38
src/PowerFSMThread.h
Normal file
38
src/PowerFSMThread.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -140,7 +140,7 @@ int32_t AirTime::runOnce()
|
||||
}
|
||||
|
||||
// Init airtime windows to all 0
|
||||
for (int i = 0; i < PERIODS_TO_LOG; i++) {
|
||||
for (int i = 0; i < myNodeInfo.air_period_rx_count; i++) {
|
||||
this->airtimes.periodTX[i] = 0;
|
||||
this->airtimes.periodRX[i] = 0;
|
||||
this->airtimes.periodRX_ALL[i] = 0;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#define CHANNEL_UTILIZATION_PERIODS 6
|
||||
#define SECONDS_PER_PERIOD 3600
|
||||
#define PERIODS_TO_LOG 24
|
||||
#define PERIODS_TO_LOG 8
|
||||
#define MINUTES_IN_HOUR 60
|
||||
#define SECONDS_IN_MINUTE 60
|
||||
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
|
||||
|
||||
19
src/debug/axpDebug.h
Normal file
19
src/debug/axpDebug.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#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
|
||||
44
src/debug/i2cScan.h
Normal file
44
src/debug/i2cScan.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#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
|
||||
@@ -9,14 +9,45 @@
|
||||
#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
|
||||
}
|
||||
@@ -40,8 +71,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 (uint8_t y = 0; y < displayHeight; y++) {
|
||||
for (uint8_t x = 0; x < displayWidth; x++) {
|
||||
for (uint64_t y = 0; y < displayHeight; y++) {
|
||||
for (uint64_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];
|
||||
@@ -50,9 +81,28 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG("Updating eink... ");
|
||||
#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)
|
||||
// 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");
|
||||
@@ -97,14 +147,33 @@ bool EInkDisplay::connect()
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS,
|
||||
PIN_EINK_DC,
|
||||
PIN_EINK_RES,
|
||||
PIN_EINK_BUSY, SPI1);
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -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 "plugins/TextMessagePlugin.h"
|
||||
#include "modules/TextMessageModule.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 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;
|
||||
// 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;
|
||||
|
||||
// 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 drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
uint8_t plugin_frame;
|
||||
uint8_t module_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 drawPluginFrame(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`
|
||||
plugin_frame = state->transitionFrameTarget;
|
||||
module_frame = state->transitionFrameTarget;
|
||||
} else {
|
||||
// otherwise, just display the plugin frame that's aligned with the current frame
|
||||
plugin_frame = state->currentFrame;
|
||||
// DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
|
||||
// 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);
|
||||
}
|
||||
// DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
|
||||
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
|
||||
// DEBUG_MSG("Drawing Module Frame %d\n\n", module_frame);
|
||||
MeshPlugin &pi = *moduleFrames.at(module_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 plugin are enabled
|
||||
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||
static bool shouldDrawMessage(const MeshPacket *packet)
|
||||
{
|
||||
return packet->from != 0 && !radioConfig.preferences.range_test_plugin_enabled &&
|
||||
!radioConfig.preferences.store_forward_plugin_enabled;
|
||||
return packet->from != 0 && !radioConfig.preferences.range_test_module_enabled &&
|
||||
!radioConfig.preferences.store_forward_module_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 (textMessagePlugin)
|
||||
textMessageObserver.observe(textMessagePlugin);
|
||||
if (textMessageModule)
|
||||
textMessageObserver.observe(textMessageModule);
|
||||
|
||||
// Plugins can notify screen about refresh
|
||||
// Modules can notify screen about refresh
|
||||
MeshPlugin::observeUIEvents(&uiFrameEventObserver);
|
||||
}
|
||||
|
||||
@@ -976,9 +976,9 @@ void Screen::setFrames()
|
||||
DEBUG_MSG("showing standard frames\n");
|
||||
showingNormalScreen = true;
|
||||
|
||||
pluginFrames = MeshPlugin::GetMeshPluginsWithUIFrames();
|
||||
DEBUG_MSG("Showing %d plugin frames\n", pluginFrames.size());
|
||||
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + pluginFrames.size();
|
||||
moduleFrames = MeshPlugin::GetMeshModulesWithUIFrames();
|
||||
DEBUG_MSG("Showing %d module frames\n", moduleFrames.size());
|
||||
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.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 plugin frames first.
|
||||
// put all of the module frames first.
|
||||
// this is a little bit of a dirty hack; since we're going to call
|
||||
// the same drawPluginFrame handler here for all of these plugin frames
|
||||
// the same drawModuleFrame handler here for all of these module frames
|
||||
// and then we'll just assume that the state->currentFrame value
|
||||
// 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;
|
||||
// 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;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
|
||||
DEBUG_MSG("Added modules. 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 plugins
|
||||
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
|
||||
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
|
||||
normalFrames[numframes++] = drawTextMessageFrame;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ void RotaryEncoderInterruptImpl1::init()
|
||||
char eventPressed =
|
||||
static_cast<char>(radioConfig.preferences.rotary1_event_press);
|
||||
|
||||
//radioConfig.preferences.ext_notification_plugin_output
|
||||
//radioConfig.preferences.ext_notification_module_output
|
||||
RotaryEncoderInterruptBase::init(
|
||||
pinA, pinB, pinPress,
|
||||
eventCw, eventCcw, eventPressed,
|
||||
|
||||
361
src/main.cpp
361
src/main.cpp
@@ -18,10 +18,12 @@
|
||||
#include "concurrency/Periodic.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "plugins/Plugins.h"
|
||||
#include "modules/Modules.h"
|
||||
#include "sleep.h"
|
||||
#include "shutdown.h"
|
||||
#include "target_specific.h"
|
||||
#include <OneButton.h>
|
||||
#include "debug/i2cScan.h"
|
||||
#include "debug/axpDebug.h"
|
||||
#include <Wire.h>
|
||||
// #include <driver/rtc_io.h>
|
||||
|
||||
@@ -48,6 +50,8 @@
|
||||
#include "SX1268Interface.h"
|
||||
#include "LLCC68Interface.h"
|
||||
|
||||
#include "ButtonThread.h"
|
||||
#include "PowerFSMThread.h"
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
@@ -70,50 +74,6 @@ 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];
|
||||
@@ -139,238 +99,6 @@ 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);
|
||||
#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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool ButtonThread::shutdown_on_long_stop = false;
|
||||
|
||||
static Periodic *ledPeriodic;
|
||||
@@ -516,22 +244,6 @@ 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)
|
||||
@@ -543,8 +255,8 @@ void setup()
|
||||
|
||||
service.init();
|
||||
|
||||
// Now that the mesh service is created, create any plugins
|
||||
setupPlugins();
|
||||
// Now that the mesh service is created, create any modules
|
||||
setupModules();
|
||||
|
||||
// Do this after service.init (because that clears error_code)
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
@@ -686,66 +398,9 @@ 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();
|
||||
#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;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "PowerStatus.h"
|
||||
#include "graphics/Screen.h"
|
||||
|
||||
extern uint8_t screen_found;
|
||||
extern bool axp192_found;
|
||||
extern bool isCharging;
|
||||
extern bool isUSBPowered;
|
||||
@@ -20,6 +21,8 @@ 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;
|
||||
|
||||
|
||||
@@ -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, 0xbf};
|
||||
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01};
|
||||
|
||||
Channels channels;
|
||||
|
||||
@@ -84,10 +84,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
|
||||
Channel &ch = getByIndex(chIndex);
|
||||
ChannelSettings &channelSettings = ch.settings;
|
||||
|
||||
// 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.modem_config = ChannelSettings_ModemConfig_LongFast; // Default to Long Range & Fast
|
||||
|
||||
channelSettings.tx_power = 0; // default
|
||||
uint8_t defaultpskIndex = 1;
|
||||
@@ -216,24 +213,27 @@ const char *Channels::getName(size_t chIndex)
|
||||
channelName = "Unset";
|
||||
else
|
||||
switch (channelSettings.modem_config) {
|
||||
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
|
||||
case ChannelSettings_ModemConfig_ShortSlow:
|
||||
channelName = "ShortSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
|
||||
case ChannelSettings_ModemConfig_ShortFast:
|
||||
channelName = "ShortFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
|
||||
channelName = "LongFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||
channelName = "LongSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
|
||||
case ChannelSettings_ModemConfig_MidSlow:
|
||||
channelName = "MediumSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
|
||||
case ChannelSettings_ModemConfig_MidFast:
|
||||
channelName = "MediumFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_LongFast:
|
||||
channelName = "LongFast";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_LongSlow:
|
||||
channelName = "LongSlow";
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_VLongSlow:
|
||||
channelName = "VLongSlow";
|
||||
break;
|
||||
default:
|
||||
channelName = "Invalid";
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "configuration.h"
|
||||
#include "FloodingRouter.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
FloodingRouter::FloodingRouter() {}
|
||||
@@ -27,11 +27,41 @@ 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)
|
||||
{
|
||||
// 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()) {
|
||||
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 (p->id != 0) {
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
|
||||
|
||||
|
||||
@@ -52,6 +52,14 @@ 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
|
||||
*/
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
#include "Channels.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
#include "modules/RoutingModule.h"
|
||||
#include <assert.h>
|
||||
|
||||
std::vector<MeshPlugin *> *MeshPlugin::plugins;
|
||||
std::vector<MeshPlugin *> *MeshPlugin::modules;
|
||||
|
||||
const MeshPacket *MeshPlugin::currentRequest;
|
||||
|
||||
/**
|
||||
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
|
||||
* If any of the current chain of modules 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 (!plugins)
|
||||
plugins = new std::vector<MeshPlugin *>();
|
||||
if (!modules)
|
||||
modules = new std::vector<MeshPlugin *>();
|
||||
|
||||
plugins->push_back(this);
|
||||
modules->push_back(this);
|
||||
}
|
||||
|
||||
void MeshPlugin::setup() {}
|
||||
|
||||
MeshPlugin::~MeshPlugin()
|
||||
{
|
||||
assert(0); // FIXME - remove from list of plugins once someone needs this feature
|
||||
assert(0); // FIXME - remove from list of modules 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 plugins\n");
|
||||
bool pluginFound = false;
|
||||
// DEBUG_MSG("In call modules\n");
|
||||
bool moduleFound = false;
|
||||
|
||||
// We now allow **encrypted** packets to pass through the plugins
|
||||
// We now allow **encrypted** packets to pass through the modules
|
||||
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 = plugins->begin(); i != plugins->end(); ++i) {
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
|
||||
pi.currentRequest = ∓
|
||||
|
||||
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||
/// We only call modules 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("Plugin '%s' wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
DEBUG_MSG("Module '%s' wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
|
||||
pluginFound = true;
|
||||
moduleFound = 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 plugins
|
||||
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel modules
|
||||
|
||||
/// 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 plugin send a reply, once that happens, remaining plugins are not
|
||||
// sniffing) also: we only let the one module send a reply, once that happens, remaining modules 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("Plugin '%s' sent a response\n", pi.name);
|
||||
DEBUG_MSG("Module '%s' sent a response\n", pi.name);
|
||||
} else {
|
||||
DEBUG_MSG("Plugin '%s' considered\n", pi.name);
|
||||
DEBUG_MSG("Module '%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("Plugin '%s' handled and skipped other processing\n", pi.name);
|
||||
DEBUG_MSG("Module '%s' handled and skipped other processing\n", pi.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -173,12 +173,12 @@ 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.
|
||||
routingPlugin->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
|
||||
routingModule->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pluginFound)
|
||||
DEBUG_MSG("No plugins interested in portnum=%d, src=%s\n",
|
||||
if (!moduleFound)
|
||||
DEBUG_MSG("No modules 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 plugin (because it ignores some replies)
|
||||
// DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,31 +222,61 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to)
|
||||
p->decoded.request_id = to.id;
|
||||
}
|
||||
|
||||
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames()
|
||||
std::vector<MeshPlugin *> MeshPlugin::GetMeshModulesWithUIFrames()
|
||||
{
|
||||
|
||||
std::vector<MeshPlugin *> pluginsWithUIFrames;
|
||||
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||
std::vector<MeshPlugin *> modulesWithUIFrames;
|
||||
if (modules) {
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
if (pi.wantUIFrame()) {
|
||||
DEBUG_MSG("Plugin wants a UI Frame\n");
|
||||
pluginsWithUIFrames.push_back(&pi);
|
||||
DEBUG_MSG("Module wants a UI Frame\n");
|
||||
modulesWithUIFrames.push_back(&pi);
|
||||
}
|
||||
}
|
||||
return pluginsWithUIFrames;
|
||||
}
|
||||
return modulesWithUIFrames;
|
||||
}
|
||||
|
||||
void MeshPlugin::observeUIEvents(
|
||||
Observer<const UIFrameEvent *> *observer)
|
||||
{
|
||||
std::vector<MeshPlugin *> pluginsWithUIFrames;
|
||||
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||
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("Plugin wants a UI Frame\n");
|
||||
DEBUG_MSG("Module 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;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,19 @@ 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.
|
||||
*/
|
||||
@@ -29,19 +42,19 @@ typedef struct _UIFrameEvent {
|
||||
bool needRedraw;
|
||||
} UIFrameEvent;
|
||||
|
||||
/** A baseclass for any mesh "plugin".
|
||||
/** A baseclass for any mesh "module".
|
||||
*
|
||||
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||
* A module allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||
*
|
||||
* A key concept for this is that your plugin should use a particular "portnum" for each message type you want to receive
|
||||
* A key concept for this is that your module should use a particular "portnum" for each message type you want to receive
|
||||
* and handle.
|
||||
*
|
||||
* 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)
|
||||
* 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)
|
||||
*/
|
||||
class MeshPlugin
|
||||
{
|
||||
static std::vector<MeshPlugin *> *plugins;
|
||||
static std::vector<MeshPlugin *> *modules;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
@@ -55,25 +68,27 @@ class MeshPlugin
|
||||
*/
|
||||
static void callPlugins(const MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
||||
|
||||
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
|
||||
static std::vector<MeshPlugin *> GetMeshModulesWithUIFrames();
|
||||
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 plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
|
||||
/** Most modules only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
|
||||
recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those
|
||||
plugins can set this to true and their handleReceived() will be called for every packet.
|
||||
modules 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 plugins should leave
|
||||
/** Also receive a copy of LOCALLY GENERATED messages - most modules should leave
|
||||
* this setting disabled - see issue #877 */
|
||||
bool loopbackOk = false;
|
||||
|
||||
/** Most plugins only understand decrypted packets. For plugins that also want to see encrypted packets, they should set this
|
||||
/** Most modules only understand decrypted packets. For modules that also want to see encrypted packets, they should set this
|
||||
* flag */
|
||||
bool encryptedOk = false;
|
||||
|
||||
@@ -86,11 +101,11 @@ class MeshPlugin
|
||||
const char *boundChannel = NULL;
|
||||
|
||||
/**
|
||||
* If this plugin is currently handling a request currentRequest will be preset
|
||||
* If this module is currently handling a request currentRequest will be preset
|
||||
* to the packet with the request. This is mostly useful for reply handlers.
|
||||
*
|
||||
* Note: this can be static because we are guaranteed to be processing only one
|
||||
* plugin at a time.
|
||||
* plumodulegin at a time.
|
||||
*/
|
||||
static const MeshPacket *currentRequest;
|
||||
|
||||
@@ -100,7 +115,7 @@ class MeshPlugin
|
||||
MeshPacket *myReply = NULL;
|
||||
|
||||
/**
|
||||
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
|
||||
* Initialize your module. This setup function is called once after all hardware and mesh protocol layers have
|
||||
* been initialized
|
||||
*/
|
||||
virtual void setup();
|
||||
@@ -135,10 +150,23 @@ 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 plugins has already sent a reply, it will be here. This is useful to allow
|
||||
* the RoutingPlugin to avoid sending redundant acks
|
||||
* 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
|
||||
*/
|
||||
static MeshPacket *currentReply;
|
||||
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
// Map from old region names to new region enums
|
||||
struct RegionInfo {
|
||||
RegionCode code;
|
||||
uint8_t numChannels;
|
||||
uint8_t powerLimit; // Or zero for not set
|
||||
float freq;
|
||||
float freqStart;
|
||||
float freqEnd;
|
||||
float dutyCycle;
|
||||
float spacing;
|
||||
uint8_t powerLimit; // Or zero for not set
|
||||
bool audioPermitted;
|
||||
bool freqSwitching;
|
||||
const char *name; // EU433 etc
|
||||
};
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#include "RTC.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/NodeInfoPlugin.h"
|
||||
#include "plugins/PositionPlugin.h"
|
||||
#include "modules/NodeInfoModule.h"
|
||||
#include "modules/PositionModule.h"
|
||||
#include "power.h"
|
||||
|
||||
/*
|
||||
@@ -115,10 +115,10 @@ void MeshService::reloadOwner()
|
||||
// DEBUG_MSG("reloadOwner()\n");
|
||||
// update our local data directly
|
||||
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
|
||||
assert(nodeInfoPlugin);
|
||||
assert(nodeInfoModule);
|
||||
// update everyone else
|
||||
if (nodeInfoPlugin)
|
||||
nodeInfoPlugin->sendOurNodeInfo();
|
||||
if (nodeInfoModule)
|
||||
nodeInfoModule->sendOurNodeInfo();
|
||||
nodeDB.saveToDisk();
|
||||
}
|
||||
|
||||
@@ -175,14 +175,14 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
assert(node);
|
||||
|
||||
if (node->has_position) {
|
||||
if (positionPlugin) {
|
||||
if (positionModule) {
|
||||
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
positionPlugin->sendOurPosition(dest, wantReplies);
|
||||
positionModule->sendOurPosition(dest, wantReplies);
|
||||
}
|
||||
} else {
|
||||
if (nodeInfoPlugin) {
|
||||
if (nodeInfoModule) {
|
||||
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
||||
nodeInfoModule->sendOurNodeInfo(dest, wantReplies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,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 RoutingPlugin;
|
||||
friend class RoutingModule;
|
||||
};
|
||||
|
||||
extern MeshService service;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "plugins/esp32/StoreForwardPlugin.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#include <Preferences.h>
|
||||
#include <nvs_flash.h>
|
||||
#endif
|
||||
@@ -227,35 +227,8 @@ 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);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "configuration.h"
|
||||
#include "PhoneAPI.h"
|
||||
#include "Channels.h"
|
||||
#include "GPS.h"
|
||||
@@ -6,6 +5,7 @@
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
|
||||
|
||||
@@ -24,6 +24,7 @@ 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
|
||||
@@ -58,7 +59,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
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
#include "SinglePortPlugin.h"
|
||||
|
||||
/**
|
||||
* A base class for mesh plugins that assume that they are sending/receiving one particular protobuf based
|
||||
* A base class for mesh modules 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 plugin
|
||||
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your module
|
||||
* 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 plugin!\n");
|
||||
DEBUG_MSG("Error decoding protobuf module!\n");
|
||||
}
|
||||
|
||||
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;
|
||||
|
||||
@@ -140,6 +140,8 @@ bool RF95Interface::reconfigure()
|
||||
void RF95Interface::addReceiveMetadata(MeshPacket *mp)
|
||||
{
|
||||
mp->rx_snr = lora->getSNR();
|
||||
mp->rx_rssi = lround(lora->getRSSI());
|
||||
|
||||
}
|
||||
|
||||
void RF95Interface::setStandby()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "configuration.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshRadio.h"
|
||||
@@ -6,45 +5,95 @@
|
||||
#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, spacing, num_ch, power_limit) \
|
||||
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \
|
||||
{ \
|
||||
RegionCode_##name, num_ch, power_limit, freq, spacing, #name \
|
||||
RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, #name \
|
||||
}
|
||||
|
||||
const RegionInfo regions[] = {
|
||||
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
|
||||
/*
|
||||
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)
|
||||
|
||||
};
|
||||
|
||||
/* 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()
|
||||
@@ -54,8 +103,6 @@ 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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,6 +219,9 @@ 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);
|
||||
|
||||
@@ -274,38 +324,40 @@ void RadioInterface::applyModemConfig()
|
||||
auto channelSettings = channels.getPrimary();
|
||||
if (channelSettings.spread_factor == 0) {
|
||||
switch (channelSettings.modem_config) {
|
||||
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
|
||||
///< range
|
||||
bw = 125;
|
||||
cr = 5;
|
||||
case ChannelSettings_ModemConfig_ShortFast:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 7;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
|
||||
///< range
|
||||
bw = 500;
|
||||
cr = 5;
|
||||
sf = 7;
|
||||
case ChannelSettings_ModemConfig_ShortSlow:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 8;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
|
||||
///< range
|
||||
bw = 31.25;
|
||||
case ChannelSettings_ModemConfig_MidFast:
|
||||
bw = 250;
|
||||
cr = 8;
|
||||
sf = 9;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||
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:
|
||||
bw = 125;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr46Sf2048:
|
||||
bw = 250;
|
||||
cr = 6;
|
||||
sf = 11;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw250Cr47Sf1024:
|
||||
bw = 250;
|
||||
cr = 7;
|
||||
sf = 10;
|
||||
case ChannelSettings_ModemConfig_VLongSlow:
|
||||
bw = 31.25;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
default:
|
||||
assert(0); // Unknown enum
|
||||
@@ -322,25 +374,26 @@ 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)));
|
||||
|
||||
// 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) % myRegion->numChannels;
|
||||
float freq = myRegion->freq + radioConfig.preferences.frequency_offset + myRegion->spacing * channel_num;
|
||||
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);
|
||||
|
||||
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->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 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 channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", getFreq()); // the frequency could be overridden in RadioInterface::getFreq() for some modules
|
||||
DEBUG_MSG("Radio frequency: %f\n", getFreq());
|
||||
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "RTC.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
#include "modules/RoutingModule.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)
|
||||
{
|
||||
routingPlugin->sendAckNak(err, to, idFrom, chIndex);
|
||||
routingModule->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 plugins here
|
||||
// call modules here
|
||||
MeshPlugin::callPlugins(*p, src);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class Router : protected concurrency::OSThread
|
||||
void enqueueReceivedMessage(MeshPacket *p);
|
||||
|
||||
protected:
|
||||
friend class RoutingPlugin;
|
||||
friend class RoutingModule;
|
||||
|
||||
/**
|
||||
* 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 RoutingPlugin and do the filtering there using the regular plugin logic
|
||||
* FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic
|
||||
*
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "Router.h"
|
||||
|
||||
/**
|
||||
* Most plugins are only interested in sending/receving one particular portnum. This baseclass simplifies that common
|
||||
* Most modules are only interested in sending/receving one particular portnum. This baseclass simplifies that common
|
||||
* case.
|
||||
*/
|
||||
class SinglePortPlugin : public MeshPlugin
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#ifndef PB_ADMIN_PB_H_INCLUDED
|
||||
#define PB_ADMIN_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
#include "cannedmessages.pb.h"
|
||||
#include "channel.pb.h"
|
||||
#include "mesh.pb.h"
|
||||
#include "radioconfig.pb.h"
|
||||
@@ -30,21 +29,18 @@ typedef struct _AdminMessage {
|
||||
bool confirm_set_radio;
|
||||
bool exit_simulator;
|
||||
int32_t reboot_seconds;
|
||||
bool get_canned_message_plugin_part1_request;
|
||||
CannedMessagePluginMessagePart1 get_canned_message_plugin_part1_response;
|
||||
bool get_canned_message_plugin_part2_request;
|
||||
CannedMessagePluginMessagePart2 get_canned_message_plugin_part2_response;
|
||||
bool get_canned_message_plugin_part3_request;
|
||||
CannedMessagePluginMessagePart3 get_canned_message_plugin_part3_response;
|
||||
bool get_canned_message_plugin_part4_request;
|
||||
CannedMessagePluginMessagePart4 get_canned_message_plugin_part4_response;
|
||||
bool get_canned_message_plugin_part5_request;
|
||||
CannedMessagePluginMessagePart5 get_canned_message_plugin_part5_response;
|
||||
CannedMessagePluginMessagePart1 set_canned_message_plugin_part1;
|
||||
CannedMessagePluginMessagePart2 set_canned_message_plugin_part2;
|
||||
CannedMessagePluginMessagePart3 set_canned_message_plugin_part3;
|
||||
CannedMessagePluginMessagePart4 set_canned_message_plugin_part4;
|
||||
CannedMessagePluginMessagePart5 set_canned_message_plugin_part5;
|
||||
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];
|
||||
int32_t shutdown_seconds;
|
||||
};
|
||||
} AdminMessage;
|
||||
@@ -72,21 +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_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_get_canned_message_plugin_part5_request_tag 44
|
||||
#define AdminMessage_get_canned_message_plugin_part5_response_tag 45
|
||||
#define AdminMessage_set_canned_message_plugin_part1_tag 46
|
||||
#define AdminMessage_set_canned_message_plugin_part2_tag 47
|
||||
#define AdminMessage_set_canned_message_plugin_part3_tag 48
|
||||
#define AdminMessage_set_canned_message_plugin_part4_tag 49
|
||||
#define AdminMessage_set_canned_message_plugin_part5_tag 50
|
||||
#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_shutdown_seconds_tag 51
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
@@ -104,21 +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_plugin_part1_request,get_canned_message_plugin_part1_request), 36) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (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, MESSAGE, (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, MESSAGE, (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, MESSAGE, (variant,get_canned_message_plugin_part4_response,get_canned_message_plugin_part4_response), 43) \
|
||||
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_plugin_part5_request,get_canned_message_plugin_part5_request), 44) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,get_canned_message_plugin_part5_response,get_canned_message_plugin_part5_response), 45) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_canned_message_plugin_part1,set_canned_message_plugin_part1), 46) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_canned_message_plugin_part2,set_canned_message_plugin_part2), 47) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_canned_message_plugin_part3,set_canned_message_plugin_part3), 48) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_canned_message_plugin_part4,set_canned_message_plugin_part4), 49) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_canned_message_plugin_part5,set_canned_message_plugin_part5), 50) \
|
||||
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, INT32, (variant,shutdown_seconds,shutdown_seconds), 51)
|
||||
#define AdminMessage_CALLBACK NULL
|
||||
#define AdminMessage_DEFAULT NULL
|
||||
@@ -128,16 +118,6 @@ X(a, STATIC, ONEOF, INT32, (variant,shutdown_seconds,shutdown_seconds),
|
||||
#define AdminMessage_variant_get_radio_response_MSGTYPE RadioConfig
|
||||
#define AdminMessage_variant_get_channel_response_MSGTYPE Channel
|
||||
#define AdminMessage_variant_get_owner_response_MSGTYPE User
|
||||
#define AdminMessage_variant_get_canned_message_plugin_part1_response_MSGTYPE CannedMessagePluginMessagePart1
|
||||
#define AdminMessage_variant_get_canned_message_plugin_part2_response_MSGTYPE CannedMessagePluginMessagePart2
|
||||
#define AdminMessage_variant_get_canned_message_plugin_part3_response_MSGTYPE CannedMessagePluginMessagePart3
|
||||
#define AdminMessage_variant_get_canned_message_plugin_part4_response_MSGTYPE CannedMessagePluginMessagePart4
|
||||
#define AdminMessage_variant_get_canned_message_plugin_part5_response_MSGTYPE CannedMessagePluginMessagePart5
|
||||
#define AdminMessage_variant_set_canned_message_plugin_part1_MSGTYPE CannedMessagePluginMessagePart1
|
||||
#define AdminMessage_variant_set_canned_message_plugin_part2_MSGTYPE CannedMessagePluginMessagePart2
|
||||
#define AdminMessage_variant_set_canned_message_plugin_part3_MSGTYPE CannedMessagePluginMessagePart3
|
||||
#define AdminMessage_variant_set_canned_message_plugin_part4_MSGTYPE CannedMessagePluginMessagePart4
|
||||
#define AdminMessage_variant_set_canned_message_plugin_part5_MSGTYPE CannedMessagePluginMessagePart5
|
||||
|
||||
extern const pb_msgdesc_t AdminMessage_msg;
|
||||
|
||||
@@ -145,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 804
|
||||
#define AdminMessage_size 611
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -6,19 +6,7 @@
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(CannedMessagePluginMessagePart1, CannedMessagePluginMessagePart1, AUTO)
|
||||
|
||||
|
||||
PB_BIND(CannedMessagePluginMessagePart2, CannedMessagePluginMessagePart2, AUTO)
|
||||
|
||||
|
||||
PB_BIND(CannedMessagePluginMessagePart3, CannedMessagePluginMessagePart3, AUTO)
|
||||
|
||||
|
||||
PB_BIND(CannedMessagePluginMessagePart4, CannedMessagePluginMessagePart4, AUTO)
|
||||
|
||||
|
||||
PB_BIND(CannedMessagePluginMessagePart5, CannedMessagePluginMessagePart5, AUTO)
|
||||
PB_BIND(CannedMessageModuleConfig, CannedMessageModuleConfig, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,25 +10,12 @@
|
||||
#endif
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _CannedMessagePluginMessagePart1 {
|
||||
char text[200];
|
||||
} CannedMessagePluginMessagePart1;
|
||||
|
||||
typedef struct _CannedMessagePluginMessagePart2 {
|
||||
char text[200];
|
||||
} CannedMessagePluginMessagePart2;
|
||||
|
||||
typedef struct _CannedMessagePluginMessagePart3 {
|
||||
char text[200];
|
||||
} CannedMessagePluginMessagePart3;
|
||||
|
||||
typedef struct _CannedMessagePluginMessagePart4 {
|
||||
char text[200];
|
||||
} CannedMessagePluginMessagePart4;
|
||||
|
||||
typedef struct _CannedMessagePluginMessagePart5 {
|
||||
char text[200];
|
||||
} CannedMessagePluginMessagePart5;
|
||||
typedef struct _CannedMessageModuleConfig {
|
||||
char messagesPart1[201];
|
||||
char messagesPart2[201];
|
||||
char messagesPart3[201];
|
||||
char messagesPart4[201];
|
||||
} CannedMessageModuleConfig;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -36,69 +23,31 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define CannedMessagePluginMessagePart1_init_default {""}
|
||||
#define CannedMessagePluginMessagePart2_init_default {""}
|
||||
#define CannedMessagePluginMessagePart3_init_default {""}
|
||||
#define CannedMessagePluginMessagePart4_init_default {""}
|
||||
#define CannedMessagePluginMessagePart5_init_default {""}
|
||||
#define CannedMessagePluginMessagePart1_init_zero {""}
|
||||
#define CannedMessagePluginMessagePart2_init_zero {""}
|
||||
#define CannedMessagePluginMessagePart3_init_zero {""}
|
||||
#define CannedMessagePluginMessagePart4_init_zero {""}
|
||||
#define CannedMessagePluginMessagePart5_init_zero {""}
|
||||
#define CannedMessageModuleConfig_init_default {"", "", "", ""}
|
||||
#define CannedMessageModuleConfig_init_zero {"", "", "", ""}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define CannedMessagePluginMessagePart1_text_tag 1
|
||||
#define CannedMessagePluginMessagePart2_text_tag 1
|
||||
#define CannedMessagePluginMessagePart3_text_tag 1
|
||||
#define CannedMessagePluginMessagePart4_text_tag 1
|
||||
#define CannedMessagePluginMessagePart5_text_tag 1
|
||||
#define CannedMessageModuleConfig_messagesPart1_tag 11
|
||||
#define CannedMessageModuleConfig_messagesPart2_tag 12
|
||||
#define CannedMessageModuleConfig_messagesPart3_tag 13
|
||||
#define CannedMessageModuleConfig_messagesPart4_tag 14
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define CannedMessagePluginMessagePart1_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, text, 1)
|
||||
#define CannedMessagePluginMessagePart1_CALLBACK NULL
|
||||
#define CannedMessagePluginMessagePart1_DEFAULT NULL
|
||||
#define CannedMessageModuleConfig_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 CannedMessagePluginMessagePart2_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, text, 1)
|
||||
#define CannedMessagePluginMessagePart2_CALLBACK NULL
|
||||
#define CannedMessagePluginMessagePart2_DEFAULT NULL
|
||||
|
||||
#define CannedMessagePluginMessagePart3_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, text, 1)
|
||||
#define CannedMessagePluginMessagePart3_CALLBACK NULL
|
||||
#define CannedMessagePluginMessagePart3_DEFAULT NULL
|
||||
|
||||
#define CannedMessagePluginMessagePart4_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, text, 1)
|
||||
#define CannedMessagePluginMessagePart4_CALLBACK NULL
|
||||
#define CannedMessagePluginMessagePart4_DEFAULT NULL
|
||||
|
||||
#define CannedMessagePluginMessagePart5_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, text, 1)
|
||||
#define CannedMessagePluginMessagePart5_CALLBACK NULL
|
||||
#define CannedMessagePluginMessagePart5_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t CannedMessagePluginMessagePart1_msg;
|
||||
extern const pb_msgdesc_t CannedMessagePluginMessagePart2_msg;
|
||||
extern const pb_msgdesc_t CannedMessagePluginMessagePart3_msg;
|
||||
extern const pb_msgdesc_t CannedMessagePluginMessagePart4_msg;
|
||||
extern const pb_msgdesc_t CannedMessagePluginMessagePart5_msg;
|
||||
extern const pb_msgdesc_t CannedMessageModuleConfig_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define CannedMessagePluginMessagePart1_fields &CannedMessagePluginMessagePart1_msg
|
||||
#define CannedMessagePluginMessagePart2_fields &CannedMessagePluginMessagePart2_msg
|
||||
#define CannedMessagePluginMessagePart3_fields &CannedMessagePluginMessagePart3_msg
|
||||
#define CannedMessagePluginMessagePart4_fields &CannedMessagePluginMessagePart4_msg
|
||||
#define CannedMessagePluginMessagePart5_fields &CannedMessagePluginMessagePart5_msg
|
||||
#define CannedMessageModuleConfig_fields &CannedMessageModuleConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define CannedMessagePluginMessagePart1_size 202
|
||||
#define CannedMessagePluginMessagePart2_size 202
|
||||
#define CannedMessagePluginMessagePart3_size 202
|
||||
#define CannedMessagePluginMessagePart4_size 202
|
||||
#define CannedMessagePluginMessagePart5_size 202
|
||||
#define CannedMessageModuleConfig_size 812
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
|
||||
/* Enum definitions */
|
||||
typedef enum _ChannelSettings_ModemConfig {
|
||||
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_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;
|
||||
|
||||
typedef enum _Channel_Role {
|
||||
@@ -50,9 +51,9 @@ typedef struct _Channel {
|
||||
|
||||
|
||||
/* Helper constants for enums */
|
||||
#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 _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_VLongSlow
|
||||
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_ShortFast
|
||||
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_ShortFast+1))
|
||||
|
||||
#define _Channel_Role_MIN Channel_Role_DISABLED
|
||||
#define _Channel_Role_MAX Channel_Role_SECONDARY
|
||||
|
||||
@@ -6,12 +6,6 @@
|
||||
#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)
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#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.
|
||||
@@ -18,18 +17,7 @@ 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;
|
||||
@@ -43,11 +31,6 @@ typedef struct _DeviceState {
|
||||
uint32_t version;
|
||||
bool no_save;
|
||||
bool did_gps_reset;
|
||||
char canned_message_plugin_message_part1[200];
|
||||
char canned_message_plugin_message_part2[200];
|
||||
char canned_message_plugin_message_part3[200];
|
||||
char canned_message_plugin_message_part4[200];
|
||||
char canned_message_plugin_message_part5[200];
|
||||
} DeviceState;
|
||||
|
||||
|
||||
@@ -56,20 +39,13 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#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 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 ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}}
|
||||
#define LegacyRadioConfig_init_zero {false, LegacyRadioConfig_LegacyPreferences_init_zero}
|
||||
#define LegacyRadioConfig_LegacyPreferences_init_zero {_RegionCode_MIN}
|
||||
#define DeviceState_init_zero {false, LegacyRadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, "", "", "", "", ""}
|
||||
#define 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 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
|
||||
@@ -78,26 +54,9 @@ extern "C" {
|
||||
#define DeviceState_version_tag 8
|
||||
#define DeviceState_no_save_tag 9
|
||||
#define DeviceState_did_gps_reset_tag 11
|
||||
#define DeviceState_canned_message_plugin_message_part1_tag 13
|
||||
#define DeviceState_canned_message_plugin_message_part2_tag 14
|
||||
#define DeviceState_canned_message_plugin_message_part3_tag 15
|
||||
#define DeviceState_canned_message_plugin_message_part4_tag 16
|
||||
#define DeviceState_canned_message_plugin_message_part5_tag 17
|
||||
|
||||
/* 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) \
|
||||
@@ -105,15 +64,9 @@ X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \
|
||||
X(a, STATIC, SINGULAR, STRING, canned_message_plugin_message_part1, 13) \
|
||||
X(a, STATIC, SINGULAR, STRING, canned_message_plugin_message_part2, 14) \
|
||||
X(a, STATIC, SINGULAR, STRING, canned_message_plugin_message_part3, 15) \
|
||||
X(a, STATIC, SINGULAR, STRING, canned_message_plugin_message_part4, 16) \
|
||||
X(a, STATIC, SINGULAR, STRING, canned_message_plugin_message_part5, 17)
|
||||
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
|
||||
@@ -126,21 +79,15 @@ 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 LegacyRadioConfig_size 4
|
||||
#define LegacyRadioConfig_LegacyPreferences_size 2
|
||||
#define DeviceState_size 11014
|
||||
#define DeviceState_size 9885
|
||||
#define ChannelFile_size 832
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -27,7 +27,7 @@ PB_BIND(MeshPacket, MeshPacket, 2)
|
||||
PB_BIND(NodeInfo, NodeInfo, AUTO)
|
||||
|
||||
|
||||
PB_BIND(MyNodeInfo, MyNodeInfo, 2)
|
||||
PB_BIND(MyNodeInfo, MyNodeInfo, AUTO)
|
||||
|
||||
|
||||
PB_BIND(LogRecord, LogRecord, AUTO)
|
||||
|
||||
@@ -152,9 +152,7 @@ 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;
|
||||
@@ -165,12 +163,18 @@ typedef struct _MyNodeInfo {
|
||||
uint32_t min_app_version;
|
||||
uint32_t max_channels;
|
||||
pb_size_t air_period_tx_count;
|
||||
uint32_t air_period_tx[24];
|
||||
uint32_t air_period_tx[8];
|
||||
pb_size_t air_period_rx_count;
|
||||
uint32_t air_period_rx[24];
|
||||
uint32_t air_period_rx[8];
|
||||
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 {
|
||||
@@ -178,6 +182,7 @@ 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;
|
||||
@@ -332,26 +337,26 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#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 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 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, 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 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 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, _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, 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, 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 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 LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
|
||||
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
||||
@@ -372,9 +377,7 @@ 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
|
||||
@@ -389,10 +392,14 @@ 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
|
||||
@@ -464,6 +471,7 @@ 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) \
|
||||
@@ -558,9 +566,7 @@ 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) \
|
||||
@@ -574,7 +580,10 @@ 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, 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)
|
||||
#define MyNodeInfo_CALLBACK NULL
|
||||
#define MyNodeInfo_DEFAULT NULL
|
||||
|
||||
@@ -645,16 +654,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 153
|
||||
#define Position_size 155
|
||||
#define User_size 97
|
||||
#define RouteDiscovery_size 40
|
||||
#define Routing_size 42
|
||||
#define Data_size 267
|
||||
#define MeshPacket_size 318
|
||||
#define NodeInfo_size 271
|
||||
#define MyNodeInfo_size 457
|
||||
#define NodeInfo_size 273
|
||||
#define MyNodeInfo_size 282
|
||||
#define LogRecord_size 81
|
||||
#define FromRadio_size 466
|
||||
#define FromRadio_size 327
|
||||
#define ToRadio_size 321
|
||||
#define ToRadio_PeerInfo_size 8
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ typedef enum _PortNum {
|
||||
PortNum_SERIAL_APP = 64,
|
||||
PortNum_STORE_FORWARD_APP = 65,
|
||||
PortNum_RANGE_TEST_APP = 66,
|
||||
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67,
|
||||
PortNum_TELEMETRY_APP = 67,
|
||||
PortNum_ZPS_APP = 68,
|
||||
PortNum_PRIVATE_APP = 256,
|
||||
PortNum_ATAK_FORWARDER = 257,
|
||||
|
||||
@@ -21,3 +21,4 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14,15 +14,24 @@ typedef enum _RegionCode {
|
||||
RegionCode_Unset = 0,
|
||||
RegionCode_US = 1,
|
||||
RegionCode_EU433 = 2,
|
||||
RegionCode_EU865 = 3,
|
||||
RegionCode_EU868 = 3,
|
||||
RegionCode_CN = 4,
|
||||
RegionCode_JP = 5,
|
||||
RegionCode_ANZ = 6,
|
||||
RegionCode_KR = 7,
|
||||
RegionCode_TW = 8,
|
||||
RegionCode_RU = 9
|
||||
RegionCode_RU = 9,
|
||||
RegionCode_IN = 10,
|
||||
RegionCode_NZ865 = 11,
|
||||
RegionCode_TH = 12
|
||||
} RegionCode;
|
||||
|
||||
typedef enum _Role {
|
||||
Role_Default = 0,
|
||||
Role_Router = 1,
|
||||
Role_Repeater = 2
|
||||
} Role;
|
||||
|
||||
typedef enum _ChargeCurrent {
|
||||
ChargeCurrent_MAUnset = 0,
|
||||
ChargeCurrent_MA100 = 1,
|
||||
@@ -90,16 +99,17 @@ typedef enum _InputEventChar {
|
||||
InputEventChar_KEY_CANCEL = 24
|
||||
} InputEventChar;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _RadioConfig_UserPreferences {
|
||||
@@ -119,6 +129,7 @@ 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;
|
||||
@@ -137,34 +148,34 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
bool debug_log_enabled;
|
||||
pb_size_t ignore_incoming_count;
|
||||
uint32_t ignore_incoming[3];
|
||||
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;
|
||||
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;
|
||||
uint32_t position_flags;
|
||||
bool is_always_powered;
|
||||
uint32_t auto_screen_carousel_secs;
|
||||
@@ -181,12 +192,12 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
InputEventChar rotary1_event_cw;
|
||||
InputEventChar rotary1_event_ccw;
|
||||
InputEventChar rotary1_event_press;
|
||||
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 canned_message_module_enabled;
|
||||
char canned_message_module_allow_input_source[16];
|
||||
bool canned_message_module_send_bell;
|
||||
bool mqtt_encryption_enabled;
|
||||
float adc_multiplier_override;
|
||||
uint32_t serialmodule_baud;
|
||||
} RadioConfig_UserPreferences;
|
||||
|
||||
typedef struct _RadioConfig {
|
||||
@@ -197,8 +208,12 @@ typedef struct _RadioConfig {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _RegionCode_MIN RegionCode_Unset
|
||||
#define _RegionCode_MAX RegionCode_RU
|
||||
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_RU+1))
|
||||
#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 _ChargeCurrent_MIN ChargeCurrent_MAUnset
|
||||
#define _ChargeCurrent_MAX ChargeCurrent_MA1320
|
||||
@@ -224,9 +239,9 @@ typedef struct _RadioConfig {
|
||||
#define _InputEventChar_MAX InputEventChar_KEY_BACK
|
||||
#define _InputEventChar_ARRAYSIZE ((InputEventChar)(InputEventChar_KEY_BACK+1))
|
||||
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MCP9808
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MCP9808+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))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -235,9 +250,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, _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_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_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, _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_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}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
||||
@@ -256,6 +271,7 @@ 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
|
||||
@@ -273,34 +289,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_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_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_position_flags_tag 150
|
||||
#define RadioConfig_UserPreferences_is_always_powered_tag 151
|
||||
#define RadioConfig_UserPreferences_auto_screen_carousel_secs_tag 152
|
||||
@@ -317,12 +333,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_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_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_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 */
|
||||
@@ -349,6 +365,7 @@ 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) \
|
||||
@@ -366,34 +383,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, 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, 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, UINT32, position_flags, 150) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_always_powered, 151) \
|
||||
X(a, STATIC, SINGULAR, UINT32, auto_screen_carousel_secs, 152) \
|
||||
@@ -410,12 +427,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_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, 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, mqtt_encryption_enabled, 174) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, adc_multiplier_override, 175)
|
||||
X(a, STATIC, SINGULAR, FLOAT, adc_multiplier_override, 175) \
|
||||
X(a, STATIC, SINGULAR, UINT32, serialmodule_baud, 176)
|
||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||
#define RadioConfig_UserPreferences_DEFAULT NULL
|
||||
|
||||
@@ -427,8 +444,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 801
|
||||
#define RadioConfig_UserPreferences_size 798
|
||||
#define RadioConfig_size 608
|
||||
#define RadioConfig_UserPreferences_size 605
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.4 */
|
||||
|
||||
#include "environmental_measurement.pb.h"
|
||||
#include "telemetry.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(EnvironmentalMeasurement, EnvironmentalMeasurement, AUTO)
|
||||
PB_BIND(Telemetry, Telemetry, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.4 */
|
||||
|
||||
#ifndef PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
|
||||
#define PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
|
||||
#ifndef PB_TELEMETRY_PB_H_INCLUDED
|
||||
#define PB_TELEMETRY_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
@@ -10,14 +10,14 @@
|
||||
#endif
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _EnvironmentalMeasurement {
|
||||
typedef struct _Telemetry {
|
||||
float temperature;
|
||||
float relative_humidity;
|
||||
float barometric_pressure;
|
||||
float gas_resistance;
|
||||
float voltage;
|
||||
float current;
|
||||
} EnvironmentalMeasurement;
|
||||
} Telemetry;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -25,35 +25,35 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define EnvironmentalMeasurement_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define EnvironmentalMeasurement_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define Telemetry_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define Telemetry_init_zero {0, 0, 0, 0, 0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#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
|
||||
#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
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define EnvironmentalMeasurement_FIELDLIST(X, a) \
|
||||
#define Telemetry_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 EnvironmentalMeasurement_CALLBACK NULL
|
||||
#define EnvironmentalMeasurement_DEFAULT NULL
|
||||
#define Telemetry_CALLBACK NULL
|
||||
#define Telemetry_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t EnvironmentalMeasurement_msg;
|
||||
extern const pb_msgdesc_t Telemetry_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define EnvironmentalMeasurement_fields &EnvironmentalMeasurement_msg
|
||||
#define Telemetry_fields &Telemetry_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define EnvironmentalMeasurement_size 30
|
||||
#define Telemetry_size 30
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
@@ -390,6 +390,9 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
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");
|
||||
}
|
||||
@@ -427,6 +430,7 @@ 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...");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +175,9 @@ 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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "configuration.h"
|
||||
#include "AdminPlugin.h"
|
||||
#include "AdminModule.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
AdminPlugin *adminPlugin;
|
||||
AdminModule *adminModule;
|
||||
|
||||
/// 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 AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
|
||||
void AdminModule::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
|
||||
{
|
||||
if (req.decoded.want_response) {
|
||||
// We create the reply here
|
||||
@@ -41,7 +41,7 @@ void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
|
||||
}
|
||||
}
|
||||
|
||||
void AdminPlugin::handleGetRadio(const MeshPacket &req)
|
||||
void AdminModule::handleGetRadio(const MeshPacket &req)
|
||||
{
|
||||
if (req.decoded.want_response) {
|
||||
// We create the reply here
|
||||
@@ -61,8 +61,11 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req)
|
||||
}
|
||||
}
|
||||
|
||||
bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
|
||||
bool AdminModule::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:
|
||||
@@ -119,14 +122,28 @@ bool AdminPlugin::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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false; // Let others look at this message also if they want
|
||||
return handled;
|
||||
}
|
||||
|
||||
void AdminPlugin::handleSetOwner(const User &o)
|
||||
void AdminModule::handleSetOwner(const User &o)
|
||||
{
|
||||
int changed = 0;
|
||||
|
||||
@@ -156,7 +173,7 @@ void AdminPlugin::handleSetOwner(const User &o)
|
||||
service.reloadOwner();
|
||||
}
|
||||
|
||||
void AdminPlugin::handleSetChannel(const Channel &cc)
|
||||
void AdminModule::handleSetChannel(const Channel &cc)
|
||||
{
|
||||
channels.setChannel(cc);
|
||||
|
||||
@@ -170,7 +187,7 @@ void AdminPlugin::handleSetChannel(const Channel &cc)
|
||||
}
|
||||
}
|
||||
|
||||
void AdminPlugin::handleSetRadio(RadioConfig &r)
|
||||
void AdminModule::handleSetRadio(RadioConfig &r)
|
||||
{
|
||||
writeSecret(r.preferences.wifi_password, radioConfig.preferences.wifi_password);
|
||||
radioConfig = r;
|
||||
@@ -178,7 +195,7 @@ void AdminPlugin::handleSetRadio(RadioConfig &r)
|
||||
service.reloadConfig();
|
||||
}
|
||||
|
||||
AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
||||
AdminModule::AdminModule() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::adminChannel;
|
||||
@@ -2,15 +2,15 @@
|
||||
#include "ProtobufPlugin.h"
|
||||
|
||||
/**
|
||||
* Routing plugin for router control messages
|
||||
* Routing module for router control messages
|
||||
*/
|
||||
class AdminPlugin : public ProtobufPlugin<AdminMessage>
|
||||
class AdminModule : public ProtobufPlugin<AdminMessage>
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
AdminPlugin();
|
||||
AdminModule();
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
@@ -28,4 +28,4 @@ class AdminPlugin : public ProtobufPlugin<AdminMessage>
|
||||
void handleGetRadio(const MeshPacket &req);
|
||||
};
|
||||
|
||||
extern AdminPlugin *adminPlugin;
|
||||
extern AdminModule *adminModule;
|
||||
538
src/modules/CannedMessageModule.cpp
Normal file
538
src/modules/CannedMessageModule.cpp
Normal file
@@ -0,0 +1,538 @@
|
||||
#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();
|
||||
}
|
||||
}
|
||||
86
src/modules/CannedMessageModule.h
Normal file
86
src/modules/CannedMessageModule.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#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;
|
||||
187
src/modules/ExternalNotificationModule.cpp
Normal file
187
src/modules/ExternalNotificationModule.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#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
|
||||
}
|
||||
@@ -7,13 +7,13 @@
|
||||
#include <functional>
|
||||
|
||||
/*
|
||||
* Radio interface for ExternalNotificationPlugin
|
||||
* Radio interface for ExternalNotificationModule
|
||||
*
|
||||
*/
|
||||
class ExternalNotificationPlugin : public SinglePortPlugin, private concurrency::OSThread
|
||||
class ExternalNotificationModule : public SinglePortPlugin, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
ExternalNotificationPlugin();
|
||||
ExternalNotificationModule();
|
||||
|
||||
void setExternalOn();
|
||||
void setExternalOff();
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
/*
|
||||
* To developers:
|
||||
* Use this to enable / disable features in your plugin that you don't want to risk checking into GitHub.
|
||||
* Use this to enable / disable features in your module that you don't want to risk checking into GitHub.
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable development more for StoreForwardPlugin
|
||||
// Enable development more for StoreForwardModule
|
||||
bool StoreForward_Dev = false;
|
||||
60
src/modules/Modules.cpp
Normal file
60
src/modules/Modules.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#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();
|
||||
}
|
||||
6
src/modules/Modules.h
Normal file
6
src/modules/Modules.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
|
||||
*/
|
||||
void setupModules();
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "configuration.h"
|
||||
#include "NodeInfoPlugin.h"
|
||||
#include "NodeInfoModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "main.h"
|
||||
|
||||
NodeInfoPlugin *nodeInfoPlugin;
|
||||
NodeInfoModule *nodeInfoModule;
|
||||
|
||||
bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, User *pptr)
|
||||
bool NodeInfoModule::handleReceivedProtobuf(const MeshPacket &mp, User *pptr)
|
||||
{
|
||||
auto p = *pptr;
|
||||
|
||||
@@ -27,7 +27,7 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, User *pptr)
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies)
|
||||
void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
// cancel any not yet sent (now stale) position packets
|
||||
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
||||
@@ -42,7 +42,7 @@ void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
MeshPacket *NodeInfoPlugin::allocReply()
|
||||
MeshPacket *NodeInfoModule::allocReply()
|
||||
{
|
||||
User &u = owner;
|
||||
|
||||
@@ -50,15 +50,15 @@ MeshPacket *NodeInfoPlugin::allocReply()
|
||||
return allocDataProtobuf(u);
|
||||
}
|
||||
|
||||
NodeInfoPlugin::NodeInfoPlugin()
|
||||
: ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoPlugin")
|
||||
NodeInfoModule::NodeInfoModule()
|
||||
: ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoModule")
|
||||
{
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(30 *
|
||||
1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
|
||||
}
|
||||
|
||||
int32_t NodeInfoPlugin::runOnce()
|
||||
int32_t NodeInfoModule::runOnce()
|
||||
{
|
||||
static uint32_t currentGeneration;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include "ProtobufPlugin.h"
|
||||
|
||||
/**
|
||||
* NodeInfo plugin for sending/receiving NodeInfos into the mesh
|
||||
* NodeInfo module for sending/receiving NodeInfos into the mesh
|
||||
*/
|
||||
class NodeInfoPlugin : public ProtobufPlugin<User>, private concurrency::OSThread
|
||||
class NodeInfoModule : public ProtobufPlugin<User>, private concurrency::OSThread
|
||||
{
|
||||
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
|
||||
PacketId prevPacketId = 0;
|
||||
@@ -14,7 +14,7 @@ class NodeInfoPlugin : public ProtobufPlugin<User>, private concurrency::OSThrea
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
NodeInfoPlugin();
|
||||
NodeInfoModule();
|
||||
|
||||
/**
|
||||
* Send our NodeInfo into the mesh
|
||||
@@ -36,4 +36,4 @@ class NodeInfoPlugin : public ProtobufPlugin<User>, private concurrency::OSThrea
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern NodeInfoPlugin *nodeInfoPlugin;
|
||||
extern NodeInfoModule *nodeInfoModule;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "PositionPlugin.h"
|
||||
#include "PositionModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
@@ -7,16 +7,16 @@
|
||||
#include "configuration.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
|
||||
PositionPlugin *positionPlugin;
|
||||
PositionModule *positionModule;
|
||||
|
||||
PositionPlugin::PositionPlugin()
|
||||
: ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin")
|
||||
PositionModule::PositionModule()
|
||||
: ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionModule")
|
||||
{
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
|
||||
}
|
||||
|
||||
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, Position *pptr)
|
||||
bool PositionModule::handleReceivedProtobuf(const MeshPacket &mp, Position *pptr)
|
||||
{
|
||||
auto p = *pptr;
|
||||
|
||||
@@ -53,7 +53,7 @@ bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, Position *pptr
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
MeshPacket *PositionPlugin::allocReply()
|
||||
MeshPacket *PositionModule::allocReply()
|
||||
{
|
||||
NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position
|
||||
assert(node->has_position);
|
||||
@@ -109,7 +109,7 @@ MeshPacket *PositionPlugin::allocReply()
|
||||
return allocDataProtobuf(p);
|
||||
}
|
||||
|
||||
void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||
void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
// cancel any not yet sent (now stale) position packets
|
||||
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
||||
@@ -124,7 +124,7 @@ void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
int32_t PositionPlugin::runOnce()
|
||||
int32_t PositionModule::runOnce()
|
||||
{
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
/**
|
||||
* Position plugin for sending/receiving positions into the mesh
|
||||
* Position module for sending/receiving positions into the mesh
|
||||
*/
|
||||
class PositionPlugin : public ProtobufPlugin<Position>, private concurrency::OSThread
|
||||
class PositionModule : public ProtobufPlugin<Position>, private concurrency::OSThread
|
||||
{
|
||||
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
|
||||
PacketId prevPacketId = 0;
|
||||
@@ -24,7 +24,7 @@ class PositionPlugin : public ProtobufPlugin<Position>, private concurrency::OST
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
PositionPlugin();
|
||||
PositionModule();
|
||||
|
||||
/**
|
||||
* Send our position into the mesh
|
||||
@@ -47,4 +47,4 @@ class PositionPlugin : public ProtobufPlugin<Position>, private concurrency::OST
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern PositionPlugin *positionPlugin;
|
||||
extern PositionModule *positionModule;
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "configuration.h"
|
||||
#include "RemoteHardwarePlugin.h"
|
||||
#include "RemoteHardwareModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
@@ -46,13 +46,13 @@ static uint64_t digitalReads(uint64_t mask)
|
||||
return res;
|
||||
}
|
||||
|
||||
RemoteHardwarePlugin::RemoteHardwarePlugin()
|
||||
RemoteHardwareModule::RemoteHardwareModule()
|
||||
: ProtobufPlugin("remotehardware", PortNum_REMOTE_HARDWARE_APP, HardwareMessage_fields), concurrency::OSThread(
|
||||
"remotehardware")
|
||||
{
|
||||
}
|
||||
|
||||
bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, HardwareMessage *pptr)
|
||||
bool RemoteHardwareModule::handleReceivedProtobuf(const MeshPacket &req, HardwareMessage *pptr)
|
||||
{
|
||||
auto p = *pptr;
|
||||
DEBUG_MSG("Received RemoteHardware typ=%d\n", p.typ);
|
||||
@@ -111,7 +111,7 @@ bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, Hardwar
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t RemoteHardwarePlugin::runOnce()
|
||||
int32_t RemoteHardwareModule::runOnce()
|
||||
{
|
||||
if (watchGpios) {
|
||||
uint32_t now = millis();
|
||||
@@ -4,9 +4,9 @@
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
/**
|
||||
* A plugin that provides easy low-level remote access to device hardware.
|
||||
* A module that provides easy low-level remote access to device hardware.
|
||||
*/
|
||||
class RemoteHardwarePlugin : public ProtobufPlugin<HardwareMessage>, private concurrency::OSThread
|
||||
class RemoteHardwareModule : public ProtobufPlugin<HardwareMessage>, private concurrency::OSThread
|
||||
{
|
||||
/// The current set of GPIOs we've been asked to watch for changes
|
||||
uint64_t watchGpios = 0;
|
||||
@@ -20,7 +20,7 @@ class RemoteHardwarePlugin : public ProtobufPlugin<HardwareMessage>, private con
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
RemoteHardwarePlugin();
|
||||
RemoteHardwareModule();
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
@@ -40,4 +40,4 @@ class RemoteHardwarePlugin : public ProtobufPlugin<HardwareMessage>, private con
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern RemoteHardwarePlugin remoteHardwarePlugin;
|
||||
extern RemoteHardwareModule remoteHardwareModule;
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "configuration.h"
|
||||
#include "ReplyPlugin.h"
|
||||
#include "ReplyModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
MeshPacket *ReplyPlugin::allocReply()
|
||||
MeshPacket *ReplyModule::allocReply()
|
||||
{
|
||||
assert(currentRequest); // should always be !NULL
|
||||
auto req = *currentRequest;
|
||||
@@ -3,19 +3,19 @@
|
||||
|
||||
|
||||
/**
|
||||
* A simple example plugin that just replies with "Message received" to any message it receives.
|
||||
* A simple example module that just replies with "Message received" to any message it receives.
|
||||
*/
|
||||
class ReplyPlugin : public SinglePortPlugin
|
||||
class ReplyModule : public SinglePortPlugin
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
ReplyPlugin() : SinglePortPlugin("reply", PortNum_REPLY_APP) {}
|
||||
ReplyModule() : SinglePortPlugin("reply", PortNum_REPLY_APP) {}
|
||||
|
||||
protected:
|
||||
|
||||
/** For reply plugin we do all of our processing in the (normally optional)
|
||||
/** For reply module we do all of our processing in the (normally optional)
|
||||
* want_replies handling
|
||||
*/
|
||||
virtual MeshPacket *allocReply() override;
|
||||
@@ -1,18 +1,18 @@
|
||||
#include "configuration.h"
|
||||
#include "RoutingPlugin.h"
|
||||
#include "RoutingModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "Router.h"
|
||||
#include "main.h"
|
||||
|
||||
RoutingPlugin *routingPlugin;
|
||||
RoutingModule *routingModule;
|
||||
|
||||
bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, Routing *r)
|
||||
bool RoutingModule::handleReceivedProtobuf(const MeshPacket &mp, Routing *r)
|
||||
{
|
||||
printPacket("Routing sniffing", &mp);
|
||||
router->sniffReceived(&mp, r);
|
||||
|
||||
// FIXME - move this to a non promsicious PhoneAPI plugin?
|
||||
// FIXME - move this to a non promsicious PhoneAPI module?
|
||||
// Note: we are careful not to send back packets that started with the phone back to the phone
|
||||
if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) {
|
||||
printPacket("Delivering rx packet", &mp);
|
||||
@@ -22,7 +22,7 @@ bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, Routing *r)
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
MeshPacket *RoutingPlugin::allocReply()
|
||||
MeshPacket *RoutingModule::allocReply()
|
||||
{
|
||||
assert(currentRequest);
|
||||
|
||||
@@ -34,14 +34,14 @@ MeshPacket *RoutingPlugin::allocReply()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
void RoutingModule::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
|
||||
{
|
||||
auto p = allocAckNak(err, to, idFrom, chIndex);
|
||||
|
||||
router->sendLocal(p); // we sometimes send directly to the local node
|
||||
}
|
||||
|
||||
RoutingPlugin::RoutingPlugin() : ProtobufPlugin("routing", PortNum_ROUTING_APP, Routing_fields)
|
||||
RoutingModule::RoutingModule() : ProtobufPlugin("routing", PortNum_ROUTING_APP, Routing_fields)
|
||||
{
|
||||
isPromiscuous = true;
|
||||
}
|
||||
@@ -3,15 +3,15 @@
|
||||
#include "Channels.h"
|
||||
|
||||
/**
|
||||
* Routing plugin for router control messages
|
||||
* Routing module for router control messages
|
||||
*/
|
||||
class RoutingPlugin : public ProtobufPlugin<Routing>
|
||||
class RoutingModule : public ProtobufPlugin<Routing>
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
RoutingPlugin();
|
||||
RoutingModule();
|
||||
|
||||
void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
|
||||
|
||||
@@ -32,4 +32,4 @@ class RoutingPlugin : public ProtobufPlugin<Routing>
|
||||
virtual bool wantPacket(const MeshPacket *p) override { return true; }
|
||||
};
|
||||
|
||||
extern RoutingPlugin *routingPlugin;
|
||||
extern RoutingModule *routingModule;
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include "../mesh/generated/telemetry.pb.h"
|
||||
#include "configuration.h"
|
||||
#include "EnvironmentalMeasurementSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "BME280Sensor.h"
|
||||
#include <Adafruit_BME280.h>
|
||||
|
||||
BME280Sensor::BME280Sensor() : EnvironmentalMeasurementSensor {} {
|
||||
BME280Sensor::BME280Sensor() : TelemetrySensor {} {
|
||||
}
|
||||
|
||||
int32_t BME280Sensor::runOnce() {
|
||||
@@ -15,12 +15,12 @@ int32_t BME280Sensor::runOnce() {
|
||||
DEBUG_MSG("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
|
||||
// TODO more verbose diagnostics
|
||||
} else {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened BME280 on default i2c bus");
|
||||
DEBUG_MSG("Telemetry: Opened BME280 on default i2c bus");
|
||||
}
|
||||
return BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
bool BME280Sensor::getMeasurement(EnvironmentalMeasurement *measurement) {
|
||||
bool BME280Sensor::getMeasurement(Telemetry *measurement) {
|
||||
measurement->temperature = bme280.readTemperature();
|
||||
measurement->relative_humidity = bme280.readHumidity();
|
||||
measurement->barometric_pressure = bme280.readPressure() / 100.0F;
|
||||
15
src/modules/Telemetry/Sensor/BME280Sensor.h
Normal file
15
src/modules/Telemetry/Sensor/BME280Sensor.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#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;
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include "../mesh/generated/telemetry.pb.h"
|
||||
#include "configuration.h"
|
||||
#include "EnvironmentalMeasurementSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "BME680Sensor.h"
|
||||
#include <Adafruit_BME680.h>
|
||||
|
||||
BME680Sensor::BME680Sensor() : EnvironmentalMeasurementSensor {} {
|
||||
BME680Sensor::BME680Sensor() : TelemetrySensor {} {
|
||||
}
|
||||
|
||||
int32_t BME680Sensor::runOnce() {
|
||||
@@ -13,9 +13,9 @@ int32_t BME680Sensor::runOnce() {
|
||||
bme680Status = bme680.begin(0x76);
|
||||
if (!bme680Status) {
|
||||
DEBUG_MSG("Could not find a valid BME680 sensor, check wiring, address, sensor ID!");
|
||||
// TODO more verbose diagnosticsEnvironmentalMeasurementSensor
|
||||
// TODO more verbose TelemetrySensor
|
||||
} else {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened BME680 on default i2c bus");
|
||||
DEBUG_MSG("Telemetry: Opened BME680 on default i2c bus");
|
||||
// Set up oversampling and filter initialization
|
||||
bme680.setTemperatureOversampling(BME680_OS_8X);
|
||||
bme680.setHumidityOversampling(BME680_OS_2X);
|
||||
@@ -26,7 +26,7 @@ int32_t BME680Sensor::runOnce() {
|
||||
return (BME_680_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
|
||||
bool BME680Sensor::getMeasurement(EnvironmentalMeasurement *measurement) {
|
||||
bool BME680Sensor::getMeasurement(Telemetry *measurement) {
|
||||
measurement->temperature = bme680.readTemperature();
|
||||
measurement->relative_humidity = bme680.readHumidity();
|
||||
measurement->barometric_pressure = bme680.readPressure() / 100.0F;
|
||||
15
src/modules/Telemetry/Sensor/BME680Sensor.h
Normal file
15
src/modules/Telemetry/Sensor/BME680Sensor.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#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;
|
||||
};
|
||||
36
src/modules/Telemetry/Sensor/DHTSensor.cpp
Normal file
36
src/modules/Telemetry/Sensor/DHTSensor.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#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;
|
||||
}
|
||||
15
src/modules/Telemetry/Sensor/DHTSensor.h
Normal file
15
src/modules/Telemetry/Sensor/DHTSensor.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#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;
|
||||
};
|
||||
@@ -1,26 +1,26 @@
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include "../mesh/generated/telemetry.pb.h"
|
||||
#include "configuration.h"
|
||||
#include "MeshService.h"
|
||||
#include "EnvironmentalMeasurementSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "DallasSensor.h"
|
||||
#include <DS18B20.h>
|
||||
#include <OneWire.h>
|
||||
|
||||
DallasSensor::DallasSensor() : EnvironmentalMeasurementSensor {} {
|
||||
DallasSensor::DallasSensor() : TelemetrySensor {} {
|
||||
}
|
||||
|
||||
int32_t DallasSensor::runOnce() {
|
||||
oneWire = new OneWire(radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
|
||||
oneWire = new OneWire(radioConfig.preferences.telemetry_module_sensor_pin);
|
||||
ds18b20 = new DS18B20(oneWire);
|
||||
ds18b20->begin();
|
||||
ds18b20->setResolution(12);
|
||||
ds18b20->requestTemperatures();
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened DS18B20 on pin: %d\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
|
||||
DEBUG_MSG("Telemetry: Opened DS18B20 on pin: %d\n",
|
||||
radioConfig.preferences.telemetry_module_sensor_pin);
|
||||
return (DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
|
||||
bool DallasSensor::getMeasurement(EnvironmentalMeasurement *measurement) {
|
||||
bool DallasSensor::getMeasurement(Telemetry *measurement) {
|
||||
if (ds18b20->isConversionComplete()) {
|
||||
measurement->temperature = ds18b20->getTempC();
|
||||
measurement->relative_humidity = 0;
|
||||
17
src/modules/Telemetry/Sensor/DallasSensor.h
Normal file
17
src/modules/Telemetry/Sensor/DallasSensor.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#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;
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include "../mesh/generated/telemetry.pb.h"
|
||||
#include "configuration.h"
|
||||
#include "EnvironmentalMeasurementSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "MCP9808Sensor.h"
|
||||
#include <Adafruit_MCP9808.h>
|
||||
|
||||
MCP9808Sensor::MCP9808Sensor() : EnvironmentalMeasurementSensor {} {
|
||||
MCP9808Sensor::MCP9808Sensor() : TelemetrySensor {} {
|
||||
}
|
||||
|
||||
int32_t MCP9808Sensor::runOnce() {
|
||||
@@ -14,14 +14,14 @@ int32_t MCP9808Sensor::runOnce() {
|
||||
if (!mcp9808Status) {
|
||||
DEBUG_MSG("Could not find a valid MCP9808 sensor, check wiring, address, sensor ID!");
|
||||
} else {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened MCP9808 on default i2c bus");
|
||||
DEBUG_MSG("TelemetrySensor: Opened MCP9808 on default i2c bus");
|
||||
// Reduce resolution from 0.0625 degrees (precision) to 0.125 degrees (high).
|
||||
mcp9808.setResolution(2);
|
||||
}
|
||||
return (MCP_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
|
||||
bool MCP9808Sensor::getMeasurement(EnvironmentalMeasurement *measurement) {
|
||||
bool MCP9808Sensor::getMeasurement(Telemetry *measurement) {
|
||||
measurement->temperature = mcp9808.readTempC();
|
||||
|
||||
return true;
|
||||
15
src/modules/Telemetry/Sensor/MCP9808Sensor.h
Normal file
15
src/modules/Telemetry/Sensor/MCP9808Sensor.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#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;
|
||||
};
|
||||
12
src/modules/Telemetry/Sensor/TelemetrySensor.h
Normal file
12
src/modules/Telemetry/Sensor/TelemetrySensor.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#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;
|
||||
};
|
||||
299
src/modules/Telemetry/Telemetry.cpp
Normal file
299
src/modules/Telemetry/Telemetry.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include "../mesh/generated/telemetry.pb.h"
|
||||
#include "ProtobufPlugin.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public ProtobufPlugin<EnvironmentalMeasurement>
|
||||
class TelemetryModule : private concurrency::OSThread, public ProtobufPlugin<Telemetry>
|
||||
{
|
||||
public:
|
||||
EnvironmentalMeasurementPlugin()
|
||||
: concurrency::OSThread("EnvironmentalMeasurementPlugin"),
|
||||
ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg)
|
||||
TelemetryModule()
|
||||
: concurrency::OSThread("TelemetryModule"),
|
||||
ProtobufPlugin("Telemetry", PortNum_TELEMETRY_APP, &Telemetry_msg)
|
||||
{
|
||||
lastMeasurementPacket = nullptr;
|
||||
}
|
||||
@@ -20,12 +20,12 @@ class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public Pro
|
||||
/** Called to handle a particular incoming message
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, EnvironmentalMeasurement *p) override;
|
||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, Telemetry *p) override;
|
||||
virtual int32_t runOnce() override;
|
||||
/**
|
||||
* Send our EnvironmentalMeasurement into the mesh
|
||||
* Send our Telemetry into the mesh
|
||||
*/
|
||||
bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
bool sendOurTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
private:
|
||||
float CelsiusToFarenheit(float c);
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "configuration.h"
|
||||
#include "TextMessagePlugin.h"
|
||||
#include "TextMessageModule.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
|
||||
TextMessagePlugin *textMessagePlugin;
|
||||
TextMessageModule *textMessageModule;
|
||||
|
||||
ProcessMessage TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
||||
ProcessMessage TextMessageModule::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
DEBUG_MSG("Received text msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
|
||||
@@ -5,13 +5,13 @@
|
||||
/**
|
||||
* Text message handling for meshtastic - draws on the OLED display the most recent received message
|
||||
*/
|
||||
class TextMessagePlugin : public SinglePortPlugin, public Observable<const MeshPacket *>
|
||||
class TextMessageModule : public SinglePortPlugin, public Observable<const MeshPacket *>
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
TextMessagePlugin() : SinglePortPlugin("text", PortNum_TEXT_MESSAGE_APP) {}
|
||||
TextMessageModule() : SinglePortPlugin("text", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -22,4 +22,4 @@ class TextMessagePlugin : public SinglePortPlugin, public Observable<const MeshP
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
|
||||
};
|
||||
|
||||
extern TextMessagePlugin *textMessagePlugin;
|
||||
extern TextMessageModule *textMessageModule;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "RangeTestPlugin.h"
|
||||
#include "RangeTestModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
@@ -16,10 +16,10 @@
|
||||
As a receiver, I can receive packets from multiple senders. These packets can be saved to the Filesystem.
|
||||
*/
|
||||
|
||||
RangeTestPlugin *rangeTestPlugin;
|
||||
RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
RangeTestModule *rangeTestModule;
|
||||
RangeTestModuleRadio *rangeTestModuleRadio;
|
||||
|
||||
RangeTestPlugin::RangeTestPlugin() : concurrency::OSThread("RangeTestPlugin") {}
|
||||
RangeTestModule::RangeTestModule() : concurrency::OSThread("RangeTestModule") {}
|
||||
|
||||
uint32_t packetSequence = 0;
|
||||
|
||||
@@ -27,44 +27,44 @@ uint32_t packetSequence = 0;
|
||||
#define SEC_PER_HOUR 3600
|
||||
#define SEC_PER_MIN 60
|
||||
|
||||
int32_t RangeTestPlugin::runOnce()
|
||||
int32_t RangeTestModule::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// radioConfig.preferences.range_test_plugin_enabled = 1;
|
||||
// radioConfig.preferences.range_test_plugin_sender = 45;
|
||||
// radioConfig.preferences.range_test_plugin_save = 1;
|
||||
// radioConfig.preferences.range_test_module_enabled = 1;
|
||||
// radioConfig.preferences.range_test_module_sender = 45;
|
||||
// radioConfig.preferences.range_test_module_save = 1;
|
||||
|
||||
// Fixed position is useful when testing indoors.
|
||||
// radioConfig.preferences.fixed_position = 1;
|
||||
|
||||
uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000;
|
||||
uint32_t senderHeartbeat = radioConfig.preferences.range_test_module_sender * 1000;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
if (radioConfig.preferences.range_test_module_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
rangeTestPluginRadio = new RangeTestPluginRadio();
|
||||
rangeTestModuleRadio = new RangeTestModuleRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Sender\n");
|
||||
if (radioConfig.preferences.range_test_module_sender) {
|
||||
DEBUG_MSG("Initializing Range Test Module -- Sender\n");
|
||||
return (5000); // Sending first message 5 seconds after initilization.
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Receiver\n");
|
||||
DEBUG_MSG("Initializing Range Test Module -- Receiver\n");
|
||||
return (500);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
if (radioConfig.preferences.range_test_module_sender) {
|
||||
// If sender
|
||||
DEBUG_MSG("Range Test Plugin - Sending heartbeat every %d ms\n", (senderHeartbeat));
|
||||
DEBUG_MSG("Range Test Module - Sending heartbeat every %d ms\n", (senderHeartbeat));
|
||||
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
@@ -75,7 +75,7 @@ int32_t RangeTestPlugin::runOnce()
|
||||
|
||||
// Only send packets if the channel is less than 25% utilized.
|
||||
if (airTime->channelUtilizationPercent() < 25) {
|
||||
rangeTestPluginRadio->sendPayload();
|
||||
rangeTestModuleRadio->sendPayload();
|
||||
} else {
|
||||
DEBUG_MSG("rangeTest - Channel utilization is >25 percent. Skipping this opportunity to send.\n");
|
||||
}
|
||||
@@ -90,14 +90,14 @@ int32_t RangeTestPlugin::runOnce()
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin - Disabled\n");
|
||||
DEBUG_MSG("Range Test Module - Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
MeshPacket *RangeTestPluginRadio::allocReply()
|
||||
MeshPacket *RangeTestModuleRadio::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
@@ -105,7 +105,7 @@ MeshPacket *RangeTestPluginRadio::allocReply()
|
||||
return reply;
|
||||
}
|
||||
|
||||
void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
@@ -127,11 +127,11 @@ void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
||||
}
|
||||
|
||||
ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
ProcessMessage RangeTestModuleRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
if (radioConfig.preferences.range_test_module_enabled) {
|
||||
|
||||
/*
|
||||
auto &p = mp.decoded;
|
||||
@@ -141,7 +141,7 @@ ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_save) {
|
||||
if (radioConfig.preferences.range_test_module_save) {
|
||||
appendFile(mp);
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin Disabled\n");
|
||||
DEBUG_MSG("Range Test Module Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -183,7 +183,7 @@ ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
bool RangeTestModuleRadio::appendFile(const MeshPacket &mp)
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
|
||||
@@ -6,29 +6,29 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
class RangeTestPlugin : private concurrency::OSThread
|
||||
class RangeTestModule : private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
public:
|
||||
RangeTestPlugin();
|
||||
RangeTestModule();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern RangeTestPlugin *rangeTestPlugin;
|
||||
extern RangeTestModule *rangeTestModule;
|
||||
|
||||
/*
|
||||
* Radio interface for RangeTestPlugin
|
||||
* Radio interface for RangeTestModule
|
||||
*
|
||||
*/
|
||||
class RangeTestPluginRadio : public SinglePortPlugin
|
||||
class RangeTestModuleRadio : public SinglePortPlugin
|
||||
{
|
||||
uint32_t lastRxID = 0;
|
||||
|
||||
public:
|
||||
RangeTestPluginRadio() : SinglePortPlugin("RangeTestPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
RangeTestModuleRadio() : SinglePortPlugin("RangeTestModuleRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
@@ -55,4 +55,4 @@ class RangeTestPluginRadio : public SinglePortPlugin
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
|
||||
};
|
||||
|
||||
extern RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
extern RangeTestModuleRadio *rangeTestModuleRadio;
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "configuration.h"
|
||||
#include "SerialPlugin.h"
|
||||
#include "SerialModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
@@ -9,29 +9,29 @@
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
SerialPlugin
|
||||
SerialModule
|
||||
A simple interface to send messages over the mesh network by sending strings
|
||||
over a serial port.
|
||||
|
||||
Default is to use RX GPIO 16 and TX GPIO 17.
|
||||
|
||||
Need help with this plugin? Post your question on the Meshtastic Discourse:
|
||||
Need help with this module? Post your question on the Meshtastic Discourse:
|
||||
https://meshtastic.discourse.group
|
||||
|
||||
Basic Usage:
|
||||
|
||||
1) Enable the plugin by setting serialplugin_enabled to 1.
|
||||
2) Set the pins (serialplugin_rxd / serialplugin_rxd) for your preferred RX and TX GPIO pins.
|
||||
1) Enable the module by setting serialmodule_enabled to 1.
|
||||
2) Set the pins (serialmodule_rxd / serialmodule_rxd) for your preferred RX and TX GPIO pins.
|
||||
On tbeam, recommend to use:
|
||||
RXD 35
|
||||
TXD 15
|
||||
3) Set serialplugin_timeout to the amount of time to wait before we consider
|
||||
3) Set serialmodule_timeout to the amount of time to wait before we consider
|
||||
your packet as "done".
|
||||
4) (Optional) In SerialPlugin.h set the port to PortNum_TEXT_MESSAGE_APP if you want to
|
||||
4) (Optional) In SerialModule.h set the port to PortNum_TEXT_MESSAGE_APP if you want to
|
||||
send messages to/from the general text message channel.
|
||||
5) Connect to your device over the serial interface at 38400 8N1.
|
||||
6) Send a packet up to 240 bytes in length. This will get relayed over the mesh network.
|
||||
7) (Optional) Set serialplugin_echo to 1 and any message you send out will be echoed back
|
||||
7) (Optional) Set serialmodule_echo to 1 and any message you send out will be echoed back
|
||||
to your device.
|
||||
|
||||
TODO (in this order):
|
||||
@@ -39,7 +39,7 @@
|
||||
- This won't happen any time soon.
|
||||
|
||||
KNOWN PROBLEMS
|
||||
* Until the plugin is initilized by the startup sequence, the TX pin is in a floating
|
||||
* Until the module is initilized by the startup sequence, the TX pin is in a floating
|
||||
state. Device connected to that pin may see this as "noise".
|
||||
* Will not work on NRF and the Linux device targets.
|
||||
|
||||
@@ -48,66 +48,66 @@
|
||||
|
||||
#define RXD2 16
|
||||
#define TXD2 17
|
||||
#define SERIALPLUGIN_RX_BUFFER 128
|
||||
#define SERIALPLUGIN_STRING_MAX Constants_DATA_PAYLOAD_LEN
|
||||
#define SERIALPLUGIN_TIMEOUT 250
|
||||
#define SERIALPLUGIN_BAUD 38400
|
||||
#define SERIALPLUGIN_ACK 1
|
||||
#define SERIALMODULE_RX_BUFFER 128
|
||||
#define SERIALMODULE_STRING_MAX Constants_DATA_PAYLOAD_LEN
|
||||
#define SERIALMODULE_TIMEOUT 250
|
||||
#define SERIALMODULE_BAUD 38400
|
||||
#define SERIALMODULE_ACK 1
|
||||
|
||||
SerialPlugin *serialPlugin;
|
||||
SerialPluginRadio *serialPluginRadio;
|
||||
SerialModule *serialModule;
|
||||
SerialModuleRadio *serialModuleRadio;
|
||||
|
||||
SerialPlugin::SerialPlugin() : concurrency::OSThread("SerialPlugin") {}
|
||||
SerialModule::SerialModule() : concurrency::OSThread("SerialModule") {}
|
||||
|
||||
char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
|
||||
SerialPluginRadio::SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP)
|
||||
SerialModuleRadio::SerialModuleRadio() : SinglePortPlugin("SerialModuleRadio", PortNum_SERIAL_APP)
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::serialChannel;
|
||||
}
|
||||
|
||||
int32_t SerialPlugin::runOnce()
|
||||
int32_t SerialModule::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// radioConfig.preferences.serialplugin_enabled = 1;
|
||||
// radioConfig.preferences.serialplugin_rxd = 35;
|
||||
// radioConfig.preferences.serialplugin_txd = 15;
|
||||
// radioConfig.preferences.serialplugin_timeout = 1000;
|
||||
// radioConfig.preferences.serialplugin_echo = 1;
|
||||
// radioConfig.preferences.serialmodule_enabled = 1;
|
||||
// radioConfig.preferences.serialmodule_rxd = 35;
|
||||
// radioConfig.preferences.serialmodule_txd = 15;
|
||||
// radioConfig.preferences.serialmodule_timeout = 1000;
|
||||
// radioConfig.preferences.serialmodule_echo = 1;
|
||||
|
||||
if (radioConfig.preferences.serialplugin_enabled) {
|
||||
if (radioConfig.preferences.serialmodule_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
// Interface with the serial peripheral from in here.
|
||||
DEBUG_MSG("Initializing serial peripheral interface\n");
|
||||
|
||||
if (radioConfig.preferences.serialplugin_rxd && radioConfig.preferences.serialplugin_txd) {
|
||||
Serial2.begin(SERIALPLUGIN_BAUD, SERIAL_8N1, radioConfig.preferences.serialplugin_rxd,
|
||||
radioConfig.preferences.serialplugin_txd);
|
||||
if (radioConfig.preferences.serialmodule_rxd && radioConfig.preferences.serialmodule_txd) {
|
||||
Serial2.begin(SERIALMODULE_BAUD, SERIAL_8N1, radioConfig.preferences.serialmodule_rxd,
|
||||
radioConfig.preferences.serialmodule_txd);
|
||||
|
||||
} else {
|
||||
Serial2.begin(SERIALPLUGIN_BAUD, SERIAL_8N1, RXD2, TXD2);
|
||||
Serial2.begin(SERIALMODULE_BAUD, SERIAL_8N1, RXD2, TXD2);
|
||||
}
|
||||
|
||||
if (radioConfig.preferences.serialplugin_timeout) {
|
||||
if (radioConfig.preferences.serialmodule_timeout) {
|
||||
Serial2.setTimeout(
|
||||
radioConfig.preferences.serialplugin_timeout); // Number of MS to wait to set the timeout for the string.
|
||||
radioConfig.preferences.serialmodule_timeout); // Number of MS to wait to set the timeout for the string.
|
||||
|
||||
} else {
|
||||
Serial2.setTimeout(SERIALPLUGIN_TIMEOUT); // Number of MS to wait to set the timeout for the string.
|
||||
Serial2.setTimeout(SERIALMODULE_TIMEOUT); // Number of MS to wait to set the timeout for the string.
|
||||
}
|
||||
|
||||
Serial2.setRxBufferSize(SERIALPLUGIN_RX_BUFFER);
|
||||
Serial2.setRxBufferSize(SERIALMODULE_RX_BUFFER);
|
||||
|
||||
serialPluginRadio = new SerialPluginRadio();
|
||||
serialModuleRadio = new SerialModuleRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
@@ -118,7 +118,7 @@ int32_t SerialPlugin::runOnce()
|
||||
serialString = Serial2.readString();
|
||||
serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
|
||||
|
||||
serialPluginRadio->sendPayload();
|
||||
serialModuleRadio->sendPayload();
|
||||
|
||||
DEBUG_MSG("Received: %s\n", serialStringChar);
|
||||
}
|
||||
@@ -126,7 +126,7 @@ int32_t SerialPlugin::runOnce()
|
||||
|
||||
return (10);
|
||||
} else {
|
||||
DEBUG_MSG("Serial Plugin Disabled\n");
|
||||
DEBUG_MSG("Serial Module Disabled\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
@@ -135,7 +135,7 @@ int32_t SerialPlugin::runOnce()
|
||||
#endif
|
||||
}
|
||||
|
||||
MeshPacket *SerialPluginRadio::allocReply()
|
||||
MeshPacket *SerialModuleRadio::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
@@ -143,13 +143,13 @@ MeshPacket *SerialPluginRadio::allocReply()
|
||||
return reply;
|
||||
}
|
||||
|
||||
void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = SERIALPLUGIN_ACK;
|
||||
p->want_ack = SERIALMODULE_ACK;
|
||||
|
||||
p->decoded.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, serialStringChar, p->decoded.payload.size);
|
||||
@@ -157,11 +157,11 @@ void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
ProcessMessage SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
if (radioConfig.preferences.serialplugin_enabled) {
|
||||
if (radioConfig.preferences.serialmodule_enabled) {
|
||||
|
||||
auto &p = mp.decoded;
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
@@ -170,10 +170,10 @@ ProcessMessage SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
if (getFrom(&mp) == nodeDB.getNodeNum()) {
|
||||
|
||||
/*
|
||||
* If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX
|
||||
* If radioConfig.preferences.serialmodule_echo is true, then echo the packets that are sent out back to the TX
|
||||
* of the serial interface.
|
||||
*/
|
||||
if (radioConfig.preferences.serialplugin_echo) {
|
||||
if (radioConfig.preferences.serialmodule_echo) {
|
||||
|
||||
// For some reason, we get the packet back twice when we send out of the radio.
|
||||
// TODO: need to find out why.
|
||||
@@ -187,12 +187,12 @@ ProcessMessage SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
} else {
|
||||
|
||||
if (radioConfig.preferences.serialplugin_mode == 0 || radioConfig.preferences.serialplugin_mode == 1) {
|
||||
if (radioConfig.preferences.serialmodule_mode == 0 || radioConfig.preferences.serialmodule_mode == 1) {
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
|
||||
} else if (radioConfig.preferences.serialplugin_mode == 10) {
|
||||
} else if (radioConfig.preferences.serialmodule_mode == 10) {
|
||||
/*
|
||||
@jobionekabnoi
|
||||
Add code here to handle what gets sent out to the serial interface.
|
||||
@@ -202,7 +202,7 @@ ProcessMessage SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Serial Plugin Disabled\n");
|
||||
DEBUG_MSG("Serial Module Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,24 +6,24 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
class SerialPlugin : private concurrency::OSThread
|
||||
class SerialModule : private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
public:
|
||||
SerialPlugin();
|
||||
SerialModule();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern SerialPlugin *serialPlugin;
|
||||
extern SerialModule *serialModule;
|
||||
|
||||
/*
|
||||
* Radio interface for SerialPlugin
|
||||
* Radio interface for SerialModule
|
||||
*
|
||||
*/
|
||||
class SerialPluginRadio : public SinglePortPlugin
|
||||
class SerialModuleRadio : public SinglePortPlugin
|
||||
{
|
||||
uint32_t lastRxID = 0;
|
||||
|
||||
@@ -33,7 +33,7 @@ class SerialPluginRadio : public SinglePortPlugin
|
||||
from the main code.
|
||||
*/
|
||||
|
||||
SerialPluginRadio();
|
||||
SerialModuleRadio();
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
@@ -50,4 +50,4 @@ class SerialPluginRadio : public SinglePortPlugin
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
|
||||
};
|
||||
|
||||
extern SerialPluginRadio *serialPluginRadio;
|
||||
extern SerialModuleRadio *serialModuleRadio;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "StoreForwardPlugin.h"
|
||||
#include "StoreForwardModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
@@ -7,19 +7,19 @@
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/generated/storeforward.pb.h"
|
||||
#include "plugins/PluginDev.h"
|
||||
#include "modules/ModuleDev.h"
|
||||
#include <Arduino.h>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
|
||||
StoreForwardPlugin *storeForwardPlugin;
|
||||
StoreForwardModule *storeForwardModule;
|
||||
|
||||
int32_t StoreForwardPlugin::runOnce()
|
||||
int32_t StoreForwardModule::runOnce()
|
||||
{
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
if (radioConfig.preferences.store_forward_module_enabled) {
|
||||
|
||||
if (radioConfig.preferences.is_router) {
|
||||
|
||||
@@ -31,11 +31,11 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
if (airTime->channelUtilizationPercent() < 25) {
|
||||
|
||||
// DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
|
||||
storeForwardPlugin->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
|
||||
storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
|
||||
|
||||
if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) {
|
||||
strcpy(this->routerMessage, "** S&F - Done");
|
||||
storeForwardPlugin->sendMessage(this->busyTo, this->routerMessage);
|
||||
storeForwardModule->sendMessage(this->busyTo, this->routerMessage);
|
||||
|
||||
// DEBUG_MSG("--- --- --- In busy loop - Done \n");
|
||||
this->packetHistoryTXQueue_index = 0;
|
||||
@@ -52,13 +52,13 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
|
||||
return (this->packetTimeMax);
|
||||
} else {
|
||||
DEBUG_MSG("Store & Forward Plugin - Disabled (is_router = false)\n");
|
||||
DEBUG_MSG("Store & Forward Module - Disabled (is_router = false)\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Store & Forward Plugin - Disabled\n");
|
||||
DEBUG_MSG("Store & Forward Module - Disabled\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
@@ -70,7 +70,7 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
/*
|
||||
Create our data structure in the PSRAM.
|
||||
*/
|
||||
void StoreForwardPlugin::populatePSRAM()
|
||||
void StoreForwardModule::populatePSRAM()
|
||||
{
|
||||
/*
|
||||
For PSRAM usage, see:
|
||||
@@ -104,7 +104,7 @@ void StoreForwardPlugin::populatePSRAM()
|
||||
DEBUG_MSG(" numberOfPackets for packetHistory - %u\n", numberOfPackets);
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::historyReport()
|
||||
void StoreForwardModule::historyReport()
|
||||
{
|
||||
DEBUG_MSG("Iterating through the message history...\n");
|
||||
DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent);
|
||||
@@ -113,27 +113,27 @@ void StoreForwardPlugin::historyReport()
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void StoreForwardPlugin::historySend(uint32_t msAgo, uint32_t to)
|
||||
void StoreForwardModule::historySend(uint32_t msAgo, uint32_t to)
|
||||
{
|
||||
|
||||
// uint32_t packetsSent = 0;
|
||||
|
||||
uint32_t queueSize = storeForwardPlugin->historyQueueCreate(msAgo, to);
|
||||
uint32_t queueSize = storeForwardModule->historyQueueCreate(msAgo, to);
|
||||
|
||||
if (queueSize) {
|
||||
snprintf(this->routerMessage, 80, "** S&F - Sending %u message(s)", queueSize);
|
||||
storeForwardPlugin->sendMessage(to, this->routerMessage);
|
||||
storeForwardModule->sendMessage(to, this->routerMessage);
|
||||
|
||||
this->busy = true; // runOnce() will pickup the next steps once busy = true.
|
||||
this->busyTo = to;
|
||||
|
||||
} else {
|
||||
strcpy(this->routerMessage, "** S&F - No history to send");
|
||||
storeForwardPlugin->sendMessage(to, this->routerMessage);
|
||||
storeForwardModule->sendMessage(to, this->routerMessage);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t StoreForwardPlugin::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
{
|
||||
|
||||
// uint32_t packetHistoryTXQueueIndex = 0;
|
||||
@@ -177,7 +177,7 @@ uint32_t StoreForwardPlugin::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
return this->packetHistoryTXQueue_size;
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::historyAdd(const MeshPacket &mp)
|
||||
void StoreForwardModule::historyAdd(const MeshPacket &mp)
|
||||
{
|
||||
const auto &p = mp.decoded;
|
||||
|
||||
@@ -191,13 +191,13 @@ void StoreForwardPlugin::historyAdd(const MeshPacket &mp)
|
||||
this->packetHistoryCurrent++;
|
||||
}
|
||||
|
||||
MeshPacket *StoreForwardPlugin::allocReply()
|
||||
MeshPacket *StoreForwardModule::allocReply()
|
||||
{
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
return reply;
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::sendPayload(NodeNum dest, uint32_t packetHistory_index)
|
||||
void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index)
|
||||
{
|
||||
DEBUG_MSG("Sending S&F Payload\n");
|
||||
MeshPacket *p = allocReply();
|
||||
@@ -218,7 +218,7 @@ void StoreForwardPlugin::sendPayload(NodeNum dest, uint32_t packetHistory_index)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::sendMessage(NodeNum dest, char *str)
|
||||
void StoreForwardModule::sendMessage(NodeNum dest, char *str)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
|
||||
@@ -240,10 +240,10 @@ void StoreForwardPlugin::sendMessage(NodeNum dest, char *str)
|
||||
// HardwareMessage_init_default
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
if (radioConfig.preferences.store_forward_module_enabled) {
|
||||
|
||||
DEBUG_MSG("--- S&F Received something\n");
|
||||
|
||||
@@ -261,9 +261,9 @@ ProcessMessage StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
// Send the last 60 minutes of messages.
|
||||
if (this->busy) {
|
||||
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
|
||||
storeForwardPlugin->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
} else {
|
||||
storeForwardPlugin->historySend(1000 * 60, getFrom(&mp));
|
||||
storeForwardModule->historySend(1000 * 60, getFrom(&mp));
|
||||
}
|
||||
} else if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 'm') &&
|
||||
(p.payload.bytes[3] == 0x00)) {
|
||||
@@ -271,10 +271,10 @@ ProcessMessage StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
"01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"01234567890123456789012345678901234567890123456789012345678901234567890123456",
|
||||
sizeof(this->routerMessage));
|
||||
storeForwardPlugin->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
|
||||
} else {
|
||||
storeForwardPlugin->historyAdd(mp);
|
||||
storeForwardModule->historyAdd(mp);
|
||||
}
|
||||
|
||||
} else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) {
|
||||
@@ -285,7 +285,7 @@ ProcessMessage StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Store & Forward Plugin - Disabled\n");
|
||||
DEBUG_MSG("Store & Forward Module - Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -293,10 +293,10 @@ ProcessMessage StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlugin::handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p)
|
||||
ProcessMessage StoreForwardModule::handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p)
|
||||
{
|
||||
if (!radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
|
||||
if (!radioConfig.preferences.store_forward_module_enabled) {
|
||||
// If this module is not enabled in any capacity, don't handle the packet, and allow other modules to consume
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
@@ -323,9 +323,9 @@ ProcessMessage StoreForwardPlugin::handleReceivedProtobuf(const MeshPacket &mp,
|
||||
// Send the last 60 minutes of messages.
|
||||
if (this->busy) {
|
||||
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
|
||||
storeForwardPlugin->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
} else {
|
||||
storeForwardPlugin->historySend(1000 * 60, getFrom(&mp));
|
||||
storeForwardModule->historySend(1000 * 60, getFrom(&mp));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -377,8 +377,8 @@ ProcessMessage StoreForwardPlugin::handleReceivedProtobuf(const MeshPacket &mp,
|
||||
return ProcessMessage::STOP; // There's no need for others to look at this message.
|
||||
}
|
||||
|
||||
StoreForwardPlugin::StoreForwardPlugin()
|
||||
: SinglePortPlugin("StoreForwardPlugin", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("StoreForwardPlugin")
|
||||
StoreForwardModule::StoreForwardModule()
|
||||
: SinglePortPlugin("StoreForwardModule", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("StoreForwardModule")
|
||||
{
|
||||
|
||||
#ifndef NO_ESP32
|
||||
@@ -387,57 +387,57 @@ StoreForwardPlugin::StoreForwardPlugin()
|
||||
|
||||
if (StoreForward_Dev) {
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
radioConfig.preferences.store_forward_module_enabled = 1;
|
||||
radioConfig.preferences.is_router = 1;
|
||||
radioConfig.preferences.is_always_powered = 1;
|
||||
}
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
if (radioConfig.preferences.store_forward_module_enabled) {
|
||||
|
||||
// Router
|
||||
if (radioConfig.preferences.is_router) {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Router\n");
|
||||
DEBUG_MSG("Initializing Store & Forward Module - Enabled as Router\n");
|
||||
if (ESP.getPsramSize()) {
|
||||
if (ESP.getFreePsram() >= 1024 * 1024) {
|
||||
|
||||
// Do the startup here
|
||||
|
||||
// Maximum number of records to return.
|
||||
if (radioConfig.preferences.store_forward_plugin_history_return_max)
|
||||
this->historyReturnMax = radioConfig.preferences.store_forward_plugin_history_return_max;
|
||||
if (radioConfig.preferences.store_forward_module_history_return_max)
|
||||
this->historyReturnMax = radioConfig.preferences.store_forward_module_history_return_max;
|
||||
|
||||
// Maximum time window for records to return (in minutes)
|
||||
if (radioConfig.preferences.store_forward_plugin_history_return_window)
|
||||
this->historyReturnWindow = radioConfig.preferences.store_forward_plugin_history_return_window;
|
||||
if (radioConfig.preferences.store_forward_module_history_return_window)
|
||||
this->historyReturnWindow = radioConfig.preferences.store_forward_module_history_return_window;
|
||||
|
||||
// Maximum number of records to store in memory
|
||||
if (radioConfig.preferences.store_forward_plugin_records)
|
||||
this->records = radioConfig.preferences.store_forward_plugin_records;
|
||||
if (radioConfig.preferences.store_forward_module_records)
|
||||
this->records = radioConfig.preferences.store_forward_module_records;
|
||||
|
||||
// Maximum number of records to store in memory
|
||||
if (radioConfig.preferences.store_forward_plugin_heartbeat)
|
||||
this->heartbeat = radioConfig.preferences.store_forward_plugin_heartbeat;
|
||||
if (radioConfig.preferences.store_forward_module_heartbeat)
|
||||
this->heartbeat = radioConfig.preferences.store_forward_module_heartbeat;
|
||||
|
||||
// Popupate PSRAM with our data structures.
|
||||
this->populatePSRAM();
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
DEBUG_MSG("Store & Forward Module - Aborting Startup.\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device doesn't have PSRAM.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
DEBUG_MSG("Store & Forward Module - Aborting Startup.\n");
|
||||
}
|
||||
|
||||
// Client
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Client\n");
|
||||
DEBUG_MSG("Initializing Store & Forward Module - Enabled as Client\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -18,7 +18,7 @@ struct PacketHistoryStruct {
|
||||
pb_size_t payload_size;
|
||||
};
|
||||
|
||||
class StoreForwardPlugin : public SinglePortPlugin, private concurrency::OSThread
|
||||
class StoreForwardModule : public SinglePortPlugin, private concurrency::OSThread
|
||||
{
|
||||
// bool firstTime = 1;
|
||||
bool busy = 0;
|
||||
@@ -37,7 +37,7 @@ class StoreForwardPlugin : public SinglePortPlugin, private concurrency::OSThrea
|
||||
uint32_t packetTimeMax = 2000;
|
||||
|
||||
public:
|
||||
StoreForwardPlugin();
|
||||
StoreForwardModule();
|
||||
|
||||
/**
|
||||
Update our local reference of when we last saw that node.
|
||||
@@ -82,4 +82,4 @@ class StoreForwardPlugin : public SinglePortPlugin, private concurrency::OSThrea
|
||||
|
||||
};
|
||||
|
||||
extern StoreForwardPlugin *storeForwardPlugin;
|
||||
extern StoreForwardModule *storeForwardModule;
|
||||
@@ -1,288 +0,0 @@
|
||||
#include "configuration.h"
|
||||
#include "CannedMessagePlugin.h"
|
||||
#include "MeshService.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
|
||||
|
||||
CannedMessagePlugin *cannedMessagePlugin;
|
||||
|
||||
CannedMessagePlugin::CannedMessagePlugin()
|
||||
: SinglePortPlugin("canned", PortNum_TEXT_MESSAGE_APP),
|
||||
concurrency::OSThread("CannedMessagePlugin")
|
||||
{
|
||||
if (radioConfig.preferences.canned_message_plugin_enabled)
|
||||
{
|
||||
if(this->splitConfiguredMessages() <= 0)
|
||||
{
|
||||
radioConfig.preferences.canned_message_plugin_enabled = false;
|
||||
DEBUG_MSG("CannedMessagePlugin: No messages are configured. Plugin is disabled\n");
|
||||
return;
|
||||
}
|
||||
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 CannedMessagePlugin::splitConfiguredMessages()
|
||||
{
|
||||
int messageIndex = 0;
|
||||
int i = 0;
|
||||
|
||||
strncpy(
|
||||
this->messageStore,
|
||||
radioConfig.preferences.canned_message_plugin_messages,
|
||||
CANNED_MESSAGE_PLUGIN_MESSAGES_SIZE);
|
||||
|
||||
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]);
|
||||
|
||||
if (messageIndex >= CANNED_MESSAGE_PLUGIN_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)
|
||||
{
|
||||
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 CannedMessagePlugin::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
if (
|
||||
(strlen(radioConfig.preferences.canned_message_plugin_allow_input_source) > 0) &&
|
||||
(strcmp(radioConfig.preferences.canned_message_plugin_allow_input_source, event->source) != 0) &&
|
||||
(strcmp(radioConfig.preferences.canned_message_plugin_allow_input_source, "_any") != 0))
|
||||
{
|
||||
// Event source is not accepted.
|
||||
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 CannedMessagePlugin::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_plugin_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++;
|
||||
}
|
||||
|
||||
|
||||
// PacketId prevPacketId = p->id; // In case we need it later.
|
||||
|
||||
DEBUG_MSG("Sending message id=%d, msg=%.*s\n",
|
||||
p->id, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
int32_t CannedMessagePlugin::runOnce()
|
||||
{
|
||||
if ((!radioConfig.preferences.canned_message_plugin_enabled)
|
||||
|| (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 plugin
|
||||
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.\n");
|
||||
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\n");
|
||||
}
|
||||
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\n");
|
||||
}
|
||||
|
||||
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* CannedMessagePlugin::getCurrentMessage()
|
||||
{
|
||||
return this->messages[this->currentMessageIndex];
|
||||
}
|
||||
const char* CannedMessagePlugin::getPrevMessage()
|
||||
{
|
||||
return this->messages[this->getPrevIndex()];
|
||||
}
|
||||
const char* CannedMessagePlugin::getNextMessage()
|
||||
{
|
||||
return this->messages[this->getNextIndex()];
|
||||
}
|
||||
bool CannedMessagePlugin::shouldDraw()
|
||||
{
|
||||
if (!radioConfig.preferences.canned_message_plugin_enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (currentMessageIndex != -1) || (this->runState != CANNED_MESSAGE_RUN_STATE_INACTIVE);
|
||||
}
|
||||
|
||||
int CannedMessagePlugin::getNextIndex()
|
||||
{
|
||||
if (this->currentMessageIndex >= (this->messagesCount -1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->currentMessageIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int CannedMessagePlugin::getPrevIndex()
|
||||
{
|
||||
if (this->currentMessageIndex <= 0)
|
||||
{
|
||||
return this->messagesCount - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->currentMessageIndex - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CannedMessagePlugin::drawFrame(
|
||||
OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
displayedNodeNum = 0; // Not currently showing a node pane
|
||||
|
||||
if (cannedMessagePlugin->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, cannedMessagePlugin->getPrevMessage());
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(0 + x, 0 + y + 8, cannedMessagePlugin->getCurrentMessage());
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(0 + x, 0 + y + 24, cannedMessagePlugin->getNextMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
#include "SinglePortPlugin.h"
|
||||
#include "input/InputBroker.h"
|
||||
|
||||
enum cannedMessagePluginRunState
|
||||
{
|
||||
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_PLUGIN_MESSAGE_MAX_COUNT 50
|
||||
/**
|
||||
* Due to config-packet size restrictions we cannot have user configuration bigger
|
||||
* than Constants_DATA_PAYLOAD_LEN bytes.
|
||||
*/
|
||||
#define CANNED_MESSAGE_PLUGIN_MESSAGES_SIZE 200
|
||||
|
||||
class CannedMessagePlugin :
|
||||
public SinglePortPlugin,
|
||||
public Observable<const UIFrameEvent *>,
|
||||
private concurrency::OSThread
|
||||
{
|
||||
CallbackObserver<CannedMessagePlugin, const InputEvent *> inputObserver =
|
||||
CallbackObserver<CannedMessagePlugin, const InputEvent *>(
|
||||
this, &CannedMessagePlugin::handleInputEvent);
|
||||
public:
|
||||
CannedMessagePlugin();
|
||||
const char* getCurrentMessage();
|
||||
const char* getPrevMessage();
|
||||
const char* getNextMessage();
|
||||
bool shouldDraw();
|
||||
void eventUp();
|
||||
void eventDown();
|
||||
void eventSelect();
|
||||
|
||||
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;
|
||||
|
||||
int currentMessageIndex = -1;
|
||||
cannedMessagePluginRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
|
||||
char messageStore[CANNED_MESSAGE_PLUGIN_MESSAGES_SIZE];
|
||||
char *messages[CANNED_MESSAGE_PLUGIN_MESSAGE_MAX_COUNT];
|
||||
int messagesCount = 0;
|
||||
unsigned long lastTouchMillis = 0;
|
||||
};
|
||||
|
||||
extern CannedMessagePlugin *cannedMessagePlugin;
|
||||
@@ -1,299 +0,0 @@
|
||||
#include "EnvironmentalMeasurementPlugin.h"
|
||||
#include "../mesh/generated/environmental_measurement.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 EnvironmentalMeasurementPlugin::runOnce()
|
||||
{
|
||||
#ifndef PORTDUINO
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
/*
|
||||
radioConfig.preferences.environmental_measurement_plugin_measurement_enabled = 1;
|
||||
radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1;
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5;
|
||||
radioConfig.preferences.environmental_measurement_plugin_update_interval = 600;
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 60;
|
||||
radioConfig.preferences.environmental_measurement_plugin_display_farenheit = false;
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_pin = 13;
|
||||
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_type =
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType::
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME280;
|
||||
*/
|
||||
|
||||
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled ||
|
||||
radioConfig.preferences.environmental_measurement_plugin_screen_enabled)) {
|
||||
// If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
|
||||
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.environmental_measurement_plugin_measurement_enabled) {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Initializing\n");
|
||||
// it's possible to have this plugin enabled, only for displaying values on the screen.
|
||||
// therefore, we should only enable the sensor loop if measurement is also enabled
|
||||
switch (radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT12:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT21:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT22:
|
||||
return dhtSensor.runOnce();
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20:
|
||||
return dallasSensor.runOnce();
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME280:
|
||||
return bme280Sensor.runOnce();
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME680:
|
||||
return bme680Sensor.runOnce();
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MCP9808:
|
||||
return mcp9808Sensor.runOnce();
|
||||
default:
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin");
|
||||
return (INT32_MAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (INT32_MAX);
|
||||
} else {
|
||||
// if we somehow got to a second run of this plugin with measurement disabled, then just wait forever
|
||||
if (!radioConfig.preferences.environmental_measurement_plugin_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.environmental_measurement_plugin_read_error_count_threshold) {
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_recovery_interval > 0) {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: TEMPORARILY DISABLED; The "
|
||||
"environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in "
|
||||
"%d seconds\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold,
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval);
|
||||
sensor_read_error_count = 0;
|
||||
return (radioConfig.preferences.environmental_measurement_plugin_recovery_interval * 1000);
|
||||
}
|
||||
DEBUG_MSG("EnvironmentalMeasurement: DISABLED; The environmental_measurement_plugin_read_error_count_threshold has "
|
||||
"been exceed: %d. Reads will not be retried until after device reset\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold);
|
||||
return (INT32_MAX);
|
||||
|
||||
} else if (sensor_read_error_count > 0) {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: 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.environmental_measurement_plugin_read_error_count_threshold -
|
||||
sensor_read_error_count);
|
||||
}
|
||||
if (!sendOurEnvironmentalMeasurement()) {
|
||||
// if we failed to read the sensor, then try again
|
||||
// as soon as we can according to the maximum polling frequency
|
||||
|
||||
switch (radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT12:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT21:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT22:
|
||||
return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20:
|
||||
return (DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME280:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME680:
|
||||
return (BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_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.environmental_measurement_plugin_update_interval * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPlugin::wantUIFrame()
|
||||
{
|
||||
return radioConfig.preferences.environmental_measurement_plugin_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 EnvironmentalMeasurementPlugin::CelsiusToFarenheit(float c)
|
||||
{
|
||||
return (c * 9) / 5 + 32;
|
||||
}
|
||||
|
||||
void EnvironmentalMeasurementPlugin::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;
|
||||
}
|
||||
|
||||
EnvironmentalMeasurement lastMeasurement;
|
||||
|
||||
uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket);
|
||||
String lastSender = GetSenderName(*lastMeasurementPacket);
|
||||
|
||||
auto &p = lastMeasurementPacket->decoded;
|
||||
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, EnvironmentalMeasurement_fields, &lastMeasurement)) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
|
||||
DEBUG_MSG("EnvironmentalMeasurement: unable to decode last packet");
|
||||
return;
|
||||
}
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
String last_temp = String(lastMeasurement.temperature, 0) + "°C";
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_display_farenheit) {
|
||||
last_temp = String(CelsiusToFarenheit(lastMeasurement.temperature), 0) + "°F";
|
||||
}
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM) - 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 EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, EnvironmentalMeasurement *p)
|
||||
{
|
||||
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled ||
|
||||
radioConfig.preferences.environmental_measurement_plugin_screen_enabled)) {
|
||||
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
|
||||
return false;
|
||||
}
|
||||
|
||||
String sender = GetSenderName(mp);
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n", sender);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p->relative_humidity);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p->temperature);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->barometric_pressure: %f\n", p->barometric_pressure);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->gas_resistance: %f\n", p->gas_resistance);
|
||||
|
||||
lastMeasurementPacket = packetPool.allocCopy(mp);
|
||||
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPlugin::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
EnvironmentalMeasurement m;
|
||||
m.barometric_pressure = 0;
|
||||
m.gas_resistance = 0;
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Read data\n");
|
||||
|
||||
switch (radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20:
|
||||
if (!dallasSensor.getMeasurement(&m))
|
||||
sensor_read_error_count++;
|
||||
break;
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT12:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT21:
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT22:
|
||||
if (!dhtSensor.getMeasurement(&m))
|
||||
sensor_read_error_count++;
|
||||
break;
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME280:
|
||||
bme280Sensor.getMeasurement(&m);
|
||||
break;
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_BME680:
|
||||
bme680Sensor.getMeasurement(&m);
|
||||
break;
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MCP9808:
|
||||
mcp9808Sensor.getMeasurement(&m);
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin");
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->barometric_pressure: %f\n", m.barometric_pressure);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->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("EnvironmentalMeasurement: Sending packet to mesh");
|
||||
service.sendToMesh(p);
|
||||
return true;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user