mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-08 19:07:26 +00:00
Compare commits
170 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea40bd991c | ||
|
|
e19dd46f0f | ||
|
|
532b06c280 | ||
|
|
0cf7aaffff | ||
|
|
e2e1819ef1 | ||
|
|
31b89e2932 | ||
|
|
a021ff7eb8 | ||
|
|
bb5d0fac90 | ||
|
|
df5ed64514 | ||
|
|
9db5f9ff67 | ||
|
|
ca83a78e13 | ||
|
|
13eef9a309 | ||
|
|
2a8ac2c0c6 | ||
|
|
c97342db99 | ||
|
|
d7b2a0ed79 | ||
|
|
af0a1b5db5 | ||
|
|
9cf030d587 | ||
|
|
c04d70d5e5 | ||
|
|
2a47819fd6 | ||
|
|
4516c8f9b5 | ||
|
|
e4fdf26dc7 | ||
|
|
39d14fedc2 | ||
|
|
1da38fc748 | ||
|
|
b5f50efdcd | ||
|
|
046e691d4e | ||
|
|
e72531b090 | ||
|
|
81e320c9cf | ||
|
|
fa8cc74141 | ||
|
|
c7d9ff7cc0 | ||
|
|
8704a9d08f | ||
|
|
c0d27e2ce9 | ||
|
|
84b9028ecb | ||
|
|
4fda7098c0 | ||
|
|
8e8264efb0 | ||
|
|
54e780a6ca | ||
|
|
125eb2b784 | ||
|
|
6ea9cdc83b | ||
|
|
c0711fde69 | ||
|
|
20b8d2c4a5 | ||
|
|
73ae151971 | ||
|
|
f4806c9dd7 | ||
|
|
79532210e8 | ||
|
|
d7f26493a5 | ||
|
|
b9d025dd58 | ||
|
|
f435086a5a | ||
|
|
3dcdf372d7 | ||
|
|
cd84f2867c | ||
|
|
cafe00e463 | ||
|
|
6da4e30215 | ||
|
|
dbf0569e29 | ||
|
|
18220b88b3 | ||
|
|
665da2fb00 | ||
|
|
57ffe6622d | ||
|
|
485fec9649 | ||
|
|
bd85736226 | ||
|
|
4ec8986934 | ||
|
|
b963216764 | ||
|
|
813fd95bc8 | ||
|
|
3598c91c29 | ||
|
|
507cd1dd20 | ||
|
|
e39506824d | ||
|
|
f68a31ab28 | ||
|
|
b1181deb58 | ||
|
|
89b32dd7ee | ||
|
|
c54e87f9a2 | ||
|
|
eee7e1de57 | ||
|
|
3c60df1565 | ||
|
|
a827017bd2 | ||
|
|
95c502c658 | ||
|
|
0f573901d5 | ||
|
|
fdc9bf5783 | ||
|
|
37e0f9a325 | ||
|
|
0c06d8db3c | ||
|
|
0be4bbb369 | ||
|
|
f02ab88393 | ||
|
|
c9d4de8808 | ||
|
|
adb912b665 | ||
|
|
3f5da1e03e | ||
|
|
0a40d920e3 | ||
|
|
39311f1e40 | ||
|
|
9cd24a5646 | ||
|
|
1c0efde315 | ||
|
|
c82905bbdd | ||
|
|
275eace968 | ||
|
|
5688c8b81e | ||
|
|
8b2798abd5 | ||
|
|
6d977923b6 | ||
|
|
52dacaed37 | ||
|
|
7a381eaea1 | ||
|
|
69391e186b | ||
|
|
06f8beaa17 | ||
|
|
3798f4ca5b | ||
|
|
4fd243a6e4 | ||
|
|
d458f673be | ||
|
|
cfcb00b943 | ||
|
|
977e47d109 | ||
|
|
cfeb40f36d | ||
|
|
4fcc3ac1de | ||
|
|
f4afa6931b | ||
|
|
71be71d63d | ||
|
|
de9f7e6c39 | ||
|
|
7c8db2b501 | ||
|
|
cd653f9434 | ||
|
|
74bc05936d | ||
|
|
7aacfd66ef | ||
|
|
3636b87db0 | ||
|
|
d6bd328576 | ||
|
|
0af5b225c4 | ||
|
|
f7dcef39ce | ||
|
|
07042178d2 | ||
|
|
243878f2a0 | ||
|
|
d3f8a76cce | ||
|
|
20131a51a2 | ||
|
|
1c9a369774 | ||
|
|
dcb426f58f | ||
|
|
35bcb5297a | ||
|
|
84e3d7c276 | ||
|
|
9b03f0ac8e | ||
|
|
eb402809e2 | ||
|
|
e9c9e40624 | ||
|
|
01eed97b91 | ||
|
|
94a47dba7d | ||
|
|
bce2c9347b | ||
|
|
da8b1d41c7 | ||
|
|
3ddae5faec | ||
|
|
34faea6100 | ||
|
|
01848a9e5d | ||
|
|
10db80541f | ||
|
|
edd1268f5f | ||
|
|
11c16e8bbc | ||
|
|
7d411351c0 | ||
|
|
df21602c90 | ||
|
|
ce4ccf3cc4 | ||
|
|
a7f93de3ad | ||
|
|
8e8257adf3 | ||
|
|
e627725dfc | ||
|
|
b3ba557b8b | ||
|
|
bd03650140 | ||
|
|
42f51f33a8 | ||
|
|
8295b88d96 | ||
|
|
70313b2660 | ||
|
|
745d3775b4 | ||
|
|
aa176b6593 | ||
|
|
b0e3a7524f | ||
|
|
5ceee50bb5 | ||
|
|
ebdad76fb2 | ||
|
|
925829dc58 | ||
|
|
e04ea853dc | ||
|
|
9587729bb0 | ||
|
|
6ec368bf02 | ||
|
|
d71c7b512f | ||
|
|
349701ac14 | ||
|
|
d424fa5ea8 | ||
|
|
ca6293eefe | ||
|
|
d289e8a86f | ||
|
|
96328526b7 | ||
|
|
279c89dca3 | ||
|
|
a7a52e08d1 | ||
|
|
f6336855d0 | ||
|
|
727d8a6456 | ||
|
|
7b80b95381 | ||
|
|
2867f8fd53 | ||
|
|
cdf416cb73 | ||
|
|
7716d62018 | ||
|
|
d5f76b16b9 | ||
|
|
552406b15f | ||
|
|
9a3d558f61 | ||
|
|
85ddf3be1b | ||
|
|
3ca42b8f51 | ||
|
|
5595fb38c1 |
@@ -14,7 +14,7 @@ BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
|
|||||||
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
|
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
|
||||||
BOARDS_NRF52="lora-relay-v1"
|
BOARDS_NRF52="lora-relay-v1"
|
||||||
|
|
||||||
NUM_JOBS=2
|
NUM_JOBS=2 || true
|
||||||
|
|
||||||
OUTDIR=release/latest
|
OUTDIR=release/latest
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
We use the same channel maps as LoRaWAN (though this is not LoRaWAN).
|
We use the same channel maps as LoRaWAN (though this is not LoRaWAN).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
See [this site](https://www.rfwireless-world.com/Tutorials/LoRa-channels-list.html) for more information.
|
See [this site](https://www.rfwireless-world.com/Tutorials/LoRa-channels-list.html) for more information.
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,20 @@ cd Meshtastic-device
|
|||||||
|
|
||||||
## Decoding stack traces
|
## Decoding stack traces
|
||||||
|
|
||||||
|
### Option 1
|
||||||
|
|
||||||
If you get a crash, you can decode the addresses from the `Backtrace:` line:
|
If you get a crash, you can decode the addresses from the `Backtrace:` line:
|
||||||
|
|
||||||
1. Save the `Backtrace: 0x....` line to a file, e.g., `backtrace.txt`.
|
1. Save the `Backtrace: 0x....` line to a file, e.g., `backtrace.txt`.
|
||||||
2. Run `bin/exception_decoder.py backtrace.txt` (this uses symbols from the
|
2. Run `bin/exception_decoder.py backtrace.txt` (this uses symbols from the
|
||||||
last `firmware.elf`, so you must be running the same binary that's still in
|
last `firmware.elf`, so you must be running the same binary that's still in
|
||||||
your `.pio/build` directory).
|
your `.pio/build` directory).
|
||||||
|
|
||||||
|
### Option 2
|
||||||
|
|
||||||
|
You can run the exception decoder to monitor the serial output and decode backtraces in real time.
|
||||||
|
|
||||||
|
1. From within PlatformIO, open a new terminal.
|
||||||
|
2. At the the terminal, enter:
|
||||||
|
`pio device monitor --port /dev/cu.SLAB_USBtoUART -f esp32_exception_decoder`
|
||||||
|
Replace the value of port with the location of your serial port.
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ Packets can be sent/received either as raw binary structures or as [Protobufs](h
|
|||||||
The relevant bits of the class heirarchy are as follows
|
The relevant bits of the class heirarchy are as follows
|
||||||
|
|
||||||
* [MeshPlugin](/src/mesh/MeshPlugin.h) (in src/mesh/MeshPlugin.h) - you probably don't want to use this baseclass directly
|
* [MeshPlugin](/src/mesh/MeshPlugin.h) (in src/mesh/MeshPlugin.h) - you probably don't want to use this baseclass directly
|
||||||
* [SinglePortPlugin](/src/mesh/SinglePortPlugin.h) (in src/mesh/SinglePortPlugin.h) - for plugins that receive from a single port number (the normal case)
|
* [SinglePortPlugin](/src/mesh/SinglePortPlugin.h) (in src/mesh/SinglePortPlugin.h) - for plugins that send/receive from a single port number (the normal case)
|
||||||
* [ProtobufPlugin](/src/mesh/ProtobufPlugin.h) (in src/mesh/ProtobufPlugin.h) - for plugins that are sending/receiving a single particular Protobuf type. Inherit from this if you are using protocol buffers in your plugin.
|
* [ProtobufPlugin](/src/mesh/ProtobufPlugin.h) (in src/mesh/ProtobufPlugin.h) - for plugins that send/receive a single particular Protobuf type. Inherit from this if you are using protocol buffers in your plugin.
|
||||||
|
|
||||||
You will typically want to inherit from either SinglePortPlugin (if you are just sending raw bytes) or ProtobufPlugin (if you are sending protobufs). You'll implement your own handleReceived/handleReceivedProtobuf - probably based on the example code.
|
You will typically want to inherit from either SinglePortPlugin (if you are just sending/receiving raw bytes) or ProtobufPlugin (if you are sending/receiving protobufs). You'll implement your own handleReceived/handleReceivedProtobuf - probably based on the example code.
|
||||||
|
|
||||||
If your plugin needs to perform any operations at startup you can override and implement the setup() method to run your code.
|
If your plugin needs to perform any operations at startup you can override and implement the setup() method to run your code.
|
||||||
|
|
||||||
@@ -45,25 +45,30 @@ A number of [key services](/src/plugins) are implemented using the plugin API, t
|
|||||||
The easiest way to get started is:
|
The easiest way to get started is:
|
||||||
|
|
||||||
* [Build and install](build-instructions.md) the standard codebase from github.
|
* [Build and install](build-instructions.md) the standard codebase from github.
|
||||||
* Copy [src/plugins/ReplyPlugin.*](/src/plugins/ReplyPlugin.cpp) into src/plugins/YourPlugin.*. Then change the port number from REPLY_APP to PRIVATE_APP.
|
* Copy [src/plugins/ReplyPlugin.*](/src/plugins/ReplyPlugin.cpp) into src/plugins/YourPlugin.*. Then change the port number from *PortNum_REPLY_APP* to *PortNum_PRIVATE_APP*.
|
||||||
|
* Edit plugins/Plugins.cpp:setupPlugins() to add a call to create an instance of your plugin (see comment at head of that function)
|
||||||
* Rebuild with your new messaging goodness and install on the device
|
* Rebuild with your new messaging goodness and install on the device
|
||||||
* Use the [meshtastic commandline tool](https://github.com/meshtastic/Meshtastic-python) to send a packet to your board "meshtastic --dest 1234 --ping"
|
* Use the [meshtastic commandline tool](https://github.com/meshtastic/Meshtastic-python) to send a packet to your board, for example "*meshtastic --dest 1234 --sendping*", where *1234* is another mesh node to send the ping to.
|
||||||
|
|
||||||
## Threading
|
## Threading
|
||||||
|
|
||||||
It is very common that you would like your plugin to be invoked periodically.
|
It is very common that you would like your plugin to be invoked periodically.
|
||||||
We use a crude/basic cooperative threading system to allow this on any of our supported platforms. Simply inherit from OSThread and implement runOnce(). See the OSThread [documentation](/src/concurrency/OSThread.h) for more details. For an example consumer of this API see RemoteHardwarePlugin::runOnce.
|
We use a crude/basic cooperative threading system to allow this on any of our supported platforms. Simply inherit from OSThread and implement runOnce(). See the OSThread [documentation](/src/concurrency/OSThread.h) for more details. For an example consumer of this API see RemoteHardwarePlugin::runOnce.
|
||||||
|
|
||||||
|
## Sending messages
|
||||||
|
|
||||||
|
If you would like to proactively send messages (rather than just responding to them), just call service.sendToMesh(). For an example of this see [NodeInfoPlugin::sendOurNodeInfo(...)](/src/plugins/NodeInfoPlugin.cpp).
|
||||||
|
|
||||||
## Picking a port number
|
## Picking a port number
|
||||||
|
|
||||||
For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a unique 'portnum' for their application.
|
For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a unique 'portnum' for their application.
|
||||||
|
|
||||||
If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to [the master list](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/portnums.proto). PortNums should be assigned in the following range:
|
If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to [the master list](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/portnums.proto). PortNums should be assigned in the following range:
|
||||||
|
|
||||||
* 0-63 Core Meshtastic use, do not use for third party apps
|
* **0-63** Core Meshtastic use; do not use for third party apps
|
||||||
* 64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application
|
* **64-127** Registered 3rd party apps. Send in a pull request that adds a new entry to portnums.proto to register your application
|
||||||
* 256-511 Use one of these portnums for your private applications that you don't want to register publically
|
* **256-511** Use one of these portnums for your private applications that you don't want to register publically
|
||||||
* 1024-66559 Are reserved for use by IP tunneling (see FIXME for more information)
|
* **1024-66559** Are reserved for use by IP tunneling (see *FIXME* for more information)
|
||||||
|
|
||||||
All other values are reserved.
|
All other values are reserved.
|
||||||
|
|
||||||
@@ -73,4 +78,4 @@ If you would like to use protocol buffers to define the structures you send over
|
|||||||
|
|
||||||
* Create a new .proto file in the protos directory. You can use the existing [remote_hardware.proto](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/remote_hardware.proto) file as an example.
|
* Create a new .proto file in the protos directory. You can use the existing [remote_hardware.proto](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/remote_hardware.proto) file as an example.
|
||||||
* Run "bin/regen-protos.sh" to regenerate the C code for accessing the protocol buffers. If you don't have the required nanopb tool, follow the instructions printed by the script to get it.
|
* Run "bin/regen-protos.sh" to regenerate the C code for accessing the protocol buffers. If you don't have the required nanopb tool, follow the instructions printed by the script to get it.
|
||||||
* Done! You can now use your new protobuf just like any of the existing protobufs in meshtastic.
|
* Done! You can now use your new protobuf just like any of the existing protobufs in meshtastic.
|
||||||
|
|||||||
@@ -9,8 +9,13 @@
|
|||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
default_envs = tbeam # 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 = tbeam
|
||||||
;default_envs = heltec # 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 = tbeam0.7
|
||||||
|
;default_envs = heltec
|
||||||
|
;default_envs = tlora-v1
|
||||||
|
;default_envs = tlora-v2
|
||||||
|
;default_envs = lora-relay-v1 # nrf board
|
||||||
|
default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
; common is not currently used
|
; common is not currently used
|
||||||
@@ -65,7 +70,7 @@ lib_deps =
|
|||||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||||
https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
|
https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
|
||||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||||
https://github.com/meshtastic/RadioLib.git#8657380241bce681c33aab46598bbf13b11f876c
|
https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a
|
||||||
https://github.com/meshtastic/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206
|
https://github.com/meshtastic/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206
|
||||||
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||||
@@ -180,10 +185,10 @@ build_type = debug ; I'm debugging with ICE a lot now
|
|||||||
build_flags =
|
build_flags =
|
||||||
${arduino_base.build_flags} -Wno-unused-variable
|
${arduino_base.build_flags} -Wno-unused-variable
|
||||||
-Isrc/nrf52
|
-Isrc/nrf52
|
||||||
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
|
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
|
||||||
;-DCFG_DEBUG=3
|
;-DCFG_DEBUG=3
|
||||||
src_filter =
|
src_filter =
|
||||||
${arduino_base.src_filter} -<esp32/> -<nimble/> -<meshwifi/>
|
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/>
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
BluetoothOTA
|
BluetoothOTA
|
||||||
monitor_port = /dev/ttyACM1
|
monitor_port = /dev/ttyACM1
|
||||||
@@ -310,7 +315,17 @@ lib_deps =
|
|||||||
; The Portduino based sim environment on top of linux
|
; The Portduino based sim environment on top of linux
|
||||||
[env:linux]
|
[env:linux]
|
||||||
platform = https://github.com/geeksville/platform-portduino.git
|
platform = https://github.com/geeksville/platform-portduino.git
|
||||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<meshwifi/>
|
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/>
|
||||||
build_flags = ${arduino_base.build_flags} -O0
|
build_flags = ${arduino_base.build_flags} -O0
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = linux_x86_64
|
board = linux_x86_64
|
||||||
|
lib_deps =
|
||||||
|
${arduino_base.lib_deps}
|
||||||
|
rweather/Crypto
|
||||||
|
|
||||||
|
; The GenieBlocks LORA prototype board
|
||||||
|
[env:genieblocks_lora]
|
||||||
|
extends = esp32_base
|
||||||
|
board = genieblocks_lora
|
||||||
|
build_flags =
|
||||||
|
${esp32_base.build_flags} -D GENIEBLOCKS
|
||||||
|
|||||||
2
proto
2
proto
Submodule proto updated: dfe7bc1217...855da8701e
Submodule sdk-nrfxlib updated: 17e8453553...e6e02cb83d
@@ -1,4 +1,5 @@
|
|||||||
#include "power.h"
|
#include "power.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
@@ -268,9 +269,42 @@ bool Power::axp192Init()
|
|||||||
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
|
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
|
||||||
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
|
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
|
||||||
|
|
||||||
//axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA
|
if (radioConfig.preferences.charge_current == ChargeCurrent_MAUnset) {
|
||||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA); // There's no HW limit on the tbeam. Setting to 450mz to be a good neighbor on the usb bus.
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA100) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_100MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA190) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_190MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA280) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_280MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA360) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_360MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA450) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA550) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA630) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_630MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA700) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_700MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA780) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_780MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA880) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_880MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA960) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_960MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1000) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1000MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1080) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1080MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1160) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1160MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1240) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1240MA);
|
||||||
|
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1320) {
|
||||||
|
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
// Not connected
|
// Not connected
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace meshtastic
|
|||||||
*/
|
*/
|
||||||
enum OptionalBool { OptFalse = 0, OptTrue = 1, OptUnknown = 2 };
|
enum OptionalBool { OptFalse = 0, OptTrue = 1, OptUnknown = 2 };
|
||||||
|
|
||||||
/// Describes the state of the GPS system.
|
/// Describes the state of the Power system.
|
||||||
class PowerStatus : public Status
|
class PowerStatus : public Status
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -3,33 +3,35 @@
|
|||||||
|
|
||||||
#define periodsToLog 48
|
#define periodsToLog 48
|
||||||
|
|
||||||
// A reminder that there are 3600 seconds in an hour so I don't have
|
AirTime *airTime;
|
||||||
// to keep googling it.
|
|
||||||
// This can be changed to a smaller number to speed up testing.
|
|
||||||
//
|
|
||||||
uint32_t secondsPerPeriod = 3600;
|
uint32_t secondsPerPeriod = 3600;
|
||||||
uint32_t lastMillis = 0;
|
uint32_t lastMillis = 0;
|
||||||
uint32_t secSinceBoot = 0;
|
uint32_t secSinceBoot = 0;
|
||||||
|
|
||||||
|
// AirTime at;
|
||||||
|
|
||||||
// Don't read out of this directly. Use the helper functions.
|
// Don't read out of this directly. Use the helper functions.
|
||||||
struct airtimeStruct {
|
struct airtimeStruct {
|
||||||
uint16_t periodTX[periodsToLog];
|
uint32_t periodTX[periodsToLog]; // AirTime transmitted
|
||||||
uint16_t periodRX[periodsToLog];
|
uint32_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets)
|
||||||
uint16_t periodRX_ALL[periodsToLog];
|
uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise.
|
||||||
uint8_t lastPeriodIndex;
|
uint8_t lastPeriodIndex;
|
||||||
} airtimes;
|
} airtimes;
|
||||||
|
|
||||||
void logAirtime(reportTypes reportType, uint32_t airtime_ms)
|
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (reportType == TX_LOG) {
|
if (reportType == TX_LOG) {
|
||||||
airtimes.periodTX[0] = airtimes.periodTX[0] + round(airtime_ms / 1000);
|
DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
|
||||||
|
airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms;
|
||||||
} else if (reportType == RX_LOG) {
|
} else if (reportType == RX_LOG) {
|
||||||
airtimes.periodRX[0] = airtimes.periodRX[0] + round(airtime_ms / 1000);
|
DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
|
||||||
|
airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms;
|
||||||
} else if (reportType == RX_ALL_LOG) {
|
} else if (reportType == RX_ALL_LOG) {
|
||||||
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + round(airtime_ms / 1000);
|
DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
|
||||||
|
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms;
|
||||||
} else {
|
} else {
|
||||||
// Unknown report type
|
DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,29 +40,27 @@ uint8_t currentPeriodIndex()
|
|||||||
return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
|
return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtimeCalculator()
|
void airtimeRotatePeriod()
|
||||||
{
|
{
|
||||||
if (millis() - lastMillis > 1000) {
|
|
||||||
lastMillis = millis();
|
|
||||||
secSinceBoot++;
|
|
||||||
if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
|
|
||||||
for (int i = periodsToLog - 2; i >= 0; --i) {
|
|
||||||
airtimes.periodTX[i + 1] = airtimes.periodTX[i];
|
|
||||||
airtimes.periodRX[i + 1] = airtimes.periodRX[i];
|
|
||||||
airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i];
|
|
||||||
}
|
|
||||||
airtimes.periodTX[0] = 0;
|
|
||||||
airtimes.periodRX[0] = 0;
|
|
||||||
airtimes.periodRX_ALL[0] = 0;
|
|
||||||
|
|
||||||
airtimes.lastPeriodIndex = currentPeriodIndex();
|
if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
|
||||||
|
DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex());
|
||||||
|
|
||||||
|
for (int i = periodsToLog - 2; i >= 0; --i) {
|
||||||
|
airtimes.periodTX[i + 1] = airtimes.periodTX[i];
|
||||||
|
airtimes.periodRX[i + 1] = airtimes.periodRX[i];
|
||||||
|
airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i];
|
||||||
}
|
}
|
||||||
|
airtimes.periodTX[0] = 0;
|
||||||
|
airtimes.periodRX[0] = 0;
|
||||||
|
airtimes.periodRX_ALL[0] = 0;
|
||||||
|
|
||||||
|
airtimes.lastPeriodIndex = currentPeriodIndex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t *airtimeReport(reportTypes reportType)
|
uint32_t *airtimeReport(reportTypes reportType)
|
||||||
{
|
{
|
||||||
// currentHourIndexReset();
|
|
||||||
|
|
||||||
if (reportType == TX_LOG) {
|
if (reportType == TX_LOG) {
|
||||||
return airtimes.periodTX;
|
return airtimes.periodTX;
|
||||||
@@ -86,3 +86,22 @@ uint32_t getSecondsSinceBoot()
|
|||||||
{
|
{
|
||||||
return secSinceBoot;
|
return secSinceBoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AirTime::AirTime() : concurrency::OSThread("AirTime") {}
|
||||||
|
|
||||||
|
int32_t AirTime::runOnce()
|
||||||
|
{
|
||||||
|
//DEBUG_MSG("AirTime::runOnce()\n");
|
||||||
|
|
||||||
|
airtimeRotatePeriod();
|
||||||
|
secSinceBoot++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This actually doesn't need to be run once per second but we currently use it for the
|
||||||
|
secSinceBoot counter.
|
||||||
|
|
||||||
|
If we have a better counter of how long the device has been online (and not millis())
|
||||||
|
then we can change this to something less frequent. Maybe once ever 5 seconds?
|
||||||
|
*/
|
||||||
|
return (1000 * 1);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel.
|
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel.
|
||||||
|
|
||||||
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including
|
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including
|
||||||
other lora radios.
|
other lora radios.
|
||||||
|
|
||||||
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
|
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
|
||||||
*/
|
*/
|
||||||
@@ -26,13 +27,28 @@ enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
|
|||||||
|
|
||||||
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
|
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
|
||||||
|
|
||||||
void airtimeCalculator();
|
void airtimeRotatePeriod();
|
||||||
|
|
||||||
uint8_t currentPeriodIndex();
|
uint8_t currentPeriodIndex();
|
||||||
uint8_t getPeriodsToLog();
|
uint8_t getPeriodsToLog();
|
||||||
|
|
||||||
uint32_t getSecondsSinceBoot();
|
uint32_t getSecondsSinceBoot();
|
||||||
|
|
||||||
uint16_t *airtimeReport(reportTypes reportType);
|
uint32_t *airtimeReport(reportTypes reportType);
|
||||||
|
|
||||||
uint32_t getSecondsPerPeriod();
|
uint32_t getSecondsPerPeriod();
|
||||||
|
|
||||||
|
class AirTime : private concurrency::OSThread
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
AirTime();
|
||||||
|
|
||||||
|
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual int32_t runOnce();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern AirTime *airTime;
|
||||||
@@ -28,6 +28,8 @@ void OSThread::setup()
|
|||||||
OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_controller)
|
OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_controller)
|
||||||
: Thread(NULL, period), controller(_controller)
|
: Thread(NULL, period), controller(_controller)
|
||||||
{
|
{
|
||||||
|
assertIsSetup();
|
||||||
|
|
||||||
ThreadName = _name;
|
ThreadName = _name;
|
||||||
|
|
||||||
if (controller)
|
if (controller)
|
||||||
@@ -81,4 +83,36 @@ void OSThread::run()
|
|||||||
currentThread = NULL;
|
currentThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
|
||||||
|
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
|
||||||
|
*
|
||||||
|
* it is super important to never allocate those object statically. instead, you should explicitly
|
||||||
|
* new them at a point where you are guaranteed that other objects that this instance
|
||||||
|
* depends on have already been created.
|
||||||
|
*
|
||||||
|
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
|
||||||
|
* this makes it guaranteed that the global mainController is fully constructed first.
|
||||||
|
*/
|
||||||
|
bool hasBeenSetup;
|
||||||
|
|
||||||
|
void assertIsSetup()
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dear developer comrade - If this assert fails() that means you need to fix the following:
|
||||||
|
*
|
||||||
|
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
|
||||||
|
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
|
||||||
|
*
|
||||||
|
* it is super important to never allocate those object statically. instead, you should explicitly
|
||||||
|
* new them at a point where you are guaranteed that other objects that this instance
|
||||||
|
* depends on have already been created.
|
||||||
|
*
|
||||||
|
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
|
||||||
|
* this makes it guaranteed that the global mainController is fully constructed first.
|
||||||
|
*/
|
||||||
|
assert(hasBeenSetup);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace concurrency
|
} // namespace concurrency
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ extern InterruptableDelay mainDelay;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base threading
|
* @brief Base threading
|
||||||
*
|
*
|
||||||
* This is a pseudo threading layer that is super easy to port, well suited to our slow network and very ram & power efficient.
|
* This is a pseudo threading layer that is super easy to port, well suited to our slow network and very ram & power efficient.
|
||||||
*
|
*
|
||||||
* TODO FIXME @geeksville
|
* TODO FIXME @geeksville
|
||||||
*
|
*
|
||||||
* move more things into OSThreads
|
* move more things into OSThreads
|
||||||
* remove lock/lockguard
|
* remove lock/lockguard
|
||||||
*
|
*
|
||||||
* move typedQueue into concurrency
|
* move typedQueue into concurrency
|
||||||
* remove freertos from typedqueue
|
* remove freertos from typedqueue
|
||||||
*/
|
*/
|
||||||
@@ -42,7 +42,6 @@ class OSThread : public Thread
|
|||||||
static bool showWaiting;
|
static bool showWaiting;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// For debug printing only (might be null)
|
/// For debug printing only (might be null)
|
||||||
static const OSThread *currentThread;
|
static const OSThread *currentThread;
|
||||||
|
|
||||||
@@ -71,4 +70,19 @@ class OSThread : public Thread
|
|||||||
virtual void run();
|
virtual void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
|
||||||
|
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
|
||||||
|
*
|
||||||
|
* it is super important to never allocate those object statically. instead, you should explicitly
|
||||||
|
* new them at a point where you are guaranteed that other objects that this instance
|
||||||
|
* depends on have already been created.
|
||||||
|
*
|
||||||
|
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
|
||||||
|
* this makes it guaranteed that the global mainController is fully constructed first.
|
||||||
|
*/
|
||||||
|
extern bool hasBeenSetup;
|
||||||
|
|
||||||
|
void assertIsSetup();
|
||||||
|
|
||||||
} // namespace concurrency
|
} // namespace concurrency
|
||||||
|
|||||||
@@ -338,6 +338,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define LORA_DIO1 35 // Not really used
|
#define LORA_DIO1 35 // Not really used
|
||||||
#define LORA_DIO2 34 // Not really used
|
#define LORA_DIO2 34 // Not really used
|
||||||
|
|
||||||
|
#elif defined(GENIEBLOCKS)
|
||||||
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
|
#define HW_VENDOR "genieblocks"
|
||||||
|
#undef GPS_RX_PIN
|
||||||
|
#undef GPS_TX_PIN
|
||||||
|
#define GPS_RX_PIN 5
|
||||||
|
#define GPS_TX_PIN 18
|
||||||
|
#define GPS_RESET_N 10
|
||||||
|
#define GPS_EXTINT 23 // On MAX-M8 module pin name is EXTINT. On L70 module pin name is STANDBY.
|
||||||
|
|
||||||
|
#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||||
|
#define BATTERY_EN_PIN 14 // Voltage voltage divider enable pin connected to mosfet
|
||||||
|
|
||||||
|
#define I2C_SDA 4 // I2C pins for this board
|
||||||
|
#define I2C_SCL 2
|
||||||
|
|
||||||
|
#define LED_PIN 12 // If defined we will blink this LED
|
||||||
|
//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen --> Long press start!)
|
||||||
|
//#define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal pull-ups or pull-down resistors.
|
||||||
|
|
||||||
|
#define USE_RF95
|
||||||
|
#define LORA_DIO0 38 // a No connect on the SX1262 module
|
||||||
|
#define LORA_RESET 9
|
||||||
|
|
||||||
|
#define RF95_SCK 22
|
||||||
|
#define RF95_MISO 19
|
||||||
|
#define RF95_MOSI 13
|
||||||
|
#define RF95_NSS 21
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_NRF52840_PCA10056
|
#ifdef ARDUINO_NRF52840_PCA10056
|
||||||
@@ -365,7 +394,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#define USE_RF95
|
#define USE_RF95
|
||||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
#define LORA_RESET 23
|
#define LORA_RESET RADIOLIB_NC
|
||||||
#define LORA_DIO1 33 // Not really used
|
#define LORA_DIO1 33 // Not really used
|
||||||
#define LORA_DIO2 32 // Not really used
|
#define LORA_DIO2 32 // Not really used
|
||||||
|
|
||||||
@@ -373,7 +402,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define RF95_SCK 5
|
#define RF95_SCK 5
|
||||||
#define RF95_MISO 19
|
#define RF95_MISO 19
|
||||||
#define RF95_MOSI 27
|
#define RF95_MOSI 27
|
||||||
#define RF95_NSS 18
|
#define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ void esp32Setup()
|
|||||||
|
|
||||||
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
|
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
|
||||||
// false positives. The wait-to-sleep timeout for shutting down radios is 30 secs, so pick 45 for now.
|
// false positives. The wait-to-sleep timeout for shutting down radios is 30 secs, so pick 45 for now.
|
||||||
#define APP_WATCHDOG_SECS 45
|
// #define APP_WATCHDOG_SECS 45
|
||||||
|
#define APP_WATCHDOG_SECS 90
|
||||||
|
|
||||||
res = esp_task_wdt_init(APP_WATCHDOG_SECS, true);
|
res = esp_task_wdt_init(APP_WATCHDOG_SECS, true);
|
||||||
assert(res == ESP_OK);
|
assert(res == ESP_OK);
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ int32_t GPS::runOnce()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We've been awake too long - force sleep
|
// We've been awake too long - force sleep
|
||||||
|
now = millis();
|
||||||
auto wakeTime = getWakeTime();
|
auto wakeTime = getWakeTime();
|
||||||
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
|
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
|||||||
|
|
||||||
bool shouldSet;
|
bool shouldSet;
|
||||||
if (q > currentQuality) {
|
if (q > currentQuality) {
|
||||||
|
currentQuality = q;
|
||||||
shouldSet = true;
|
shouldSet = true;
|
||||||
DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
|
DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
|
||||||
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) {
|
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "EInkDisplay.h"
|
#include "EInkDisplay.h"
|
||||||
#include "SPILock.h"
|
#include "SPILock.h"
|
||||||
#include "epd1in54.h" // Screen specific library
|
#include "epd1in54.h" // Screen specific library
|
||||||
#include "graphics/configs.h"
|
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <TFT_eSPI.h> // Graphics library and Sprite class
|
#include <TFT_eSPI.h> // Graphics library and Sprite class
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "fonts.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "meshwifi/meshwifi.h"
|
|
||||||
#include "plugins/TextMessagePlugin.h"
|
#include "plugins/TextMessagePlugin.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "fonts.h"
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace meshtastic; /** @todo remove */
|
using namespace meshtastic; /** @todo remove */
|
||||||
|
|
||||||
@@ -42,7 +45,7 @@ namespace graphics
|
|||||||
{
|
{
|
||||||
|
|
||||||
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
|
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
|
||||||
#define IDLE_FRAMERATE 1 // in fps
|
#define IDLE_FRAMERATE 1 // in fps
|
||||||
#define COMPASS_DIAM 44
|
#define COMPASS_DIAM 44
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
@@ -177,7 +180,6 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
|
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Draw the last text message we received
|
/// Draw the last text message we received
|
||||||
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
@@ -316,7 +318,7 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
|
|||||||
display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
|
display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
|
||||||
|
|
||||||
// Draw the number of satellites
|
// Draw the number of satellites
|
||||||
sprintf(satsString, "%lu", gps->getNumSatellites());
|
sprintf(satsString, "%u", gps->getNumSatellites());
|
||||||
display->drawString(x + 34, y - 2, satsString);
|
display->drawString(x + 34, y - 2, satsString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -569,11 +571,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
uint32_t agoSecs = sinceLastSeen(node);
|
uint32_t agoSecs = sinceLastSeen(node);
|
||||||
static char lastStr[20];
|
static char lastStr[20];
|
||||||
if (agoSecs < 120) // last 2 mins?
|
if (agoSecs < 120) // last 2 mins?
|
||||||
snprintf(lastStr, sizeof(lastStr), "%lu seconds ago", agoSecs);
|
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
|
||||||
else if (agoSecs < 120 * 60) // last 2 hrs
|
else if (agoSecs < 120 * 60) // last 2 hrs
|
||||||
snprintf(lastStr, sizeof(lastStr), "%lu minutes ago", agoSecs / 60);
|
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
||||||
else
|
else
|
||||||
snprintf(lastStr, sizeof(lastStr), "%lu hours ago", agoSecs / 60 / 60);
|
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
|
||||||
|
|
||||||
static char distStr[20];
|
static char distStr[20];
|
||||||
strcpy(distStr, "? km"); // might not have location data
|
strcpy(distStr, "? km"); // might not have location data
|
||||||
@@ -747,7 +749,7 @@ void Screen::setup()
|
|||||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||||
textMessageObserver.observe(&textMessagePlugin);
|
textMessageObserver.observe(textMessagePlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::forceDisplay()
|
void Screen::forceDisplay()
|
||||||
@@ -896,10 +898,12 @@ void Screen::setFrames()
|
|||||||
// call a method on debugInfoScreen object (for more details)
|
// call a method on debugInfoScreen object (for more details)
|
||||||
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
|
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
|
||||||
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
if (isWifiAvailable()) {
|
if (isWifiAvailable()) {
|
||||||
// call a method on debugInfoScreen object (for more details)
|
// call a method on debugInfoScreen object (for more details)
|
||||||
normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline;
|
normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ui.setFrames(normalFrames, numframes);
|
ui.setFrames(normalFrames, numframes);
|
||||||
ui.enableAllIndicators();
|
ui.enableAllIndicators();
|
||||||
@@ -924,20 +928,21 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
|||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::blink() {
|
void Screen::blink()
|
||||||
|
{
|
||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
uint8_t count = 10;
|
uint8_t count = 10;
|
||||||
dispdev.setBrightness(254);
|
dispdev.setBrightness(254);
|
||||||
while(count>0) {
|
while (count > 0) {
|
||||||
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
dispdev.display();
|
dispdev.display();
|
||||||
delay(50);
|
delay(50);
|
||||||
dispdev.clear();
|
dispdev.clear();
|
||||||
dispdev.display();
|
dispdev.display();
|
||||||
delay(50);
|
delay(50);
|
||||||
count = count -1;
|
count = count - 1;
|
||||||
}
|
}
|
||||||
dispdev.setBrightness(brightness);
|
dispdev.setBrightness(brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::handlePrint(const char *text)
|
void Screen::handlePrint(const char *text)
|
||||||
@@ -1060,11 +1065,13 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) {
|
if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) {
|
||||||
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
|
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
|
||||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
|
||||||
|
|
||||||
|
// Number of connections to the AP. Default mmax for the esp32 is 4
|
||||||
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("(" + String(WiFi.softAPgetStationNum()) + "/4)"),
|
||||||
|
y + FONT_HEIGHT_SMALL * 1, "(" + String(WiFi.softAPgetStationNum()) + "/4)");
|
||||||
} else {
|
} else {
|
||||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
|
||||||
}
|
}
|
||||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("(" + String(WiFi.softAPgetStationNum()) + "/4)"),
|
|
||||||
y + FONT_HEIGHT_SMALL * 1, "(" + String(WiFi.softAPgetStationNum()) + "/4)");
|
|
||||||
|
|
||||||
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
|
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
|
||||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
|
||||||
|
|||||||
53
src/main.cpp
53
src/main.cpp
@@ -19,8 +19,7 @@
|
|||||||
#include "concurrency/Periodic.h"
|
#include "concurrency/Periodic.h"
|
||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshwifi/meshhttp.h"
|
#include "plugins/Plugins.h"
|
||||||
#include "meshwifi/meshwifi.h"
|
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include <OneButton.h>
|
#include <OneButton.h>
|
||||||
@@ -28,6 +27,8 @@
|
|||||||
// #include <driver/rtc_io.h>
|
// #include <driver/rtc_io.h>
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
|
#include "mesh/http/WebServer.h"
|
||||||
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
#include "nimble/BluetoothUtil.h"
|
#include "nimble/BluetoothUtil.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -275,6 +276,8 @@ RadioInterface *rIf = NULL;
|
|||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
concurrency::hasBeenSetup = true;
|
||||||
|
|
||||||
#ifdef SEGGER_STDOUT_CH
|
#ifdef SEGGER_STDOUT_CH
|
||||||
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
||||||
#endif
|
#endif
|
||||||
@@ -300,17 +303,20 @@ void setup()
|
|||||||
digitalWrite(RESET_OLED, 1);
|
digitalWrite(RESET_OLED, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BUTTON_PIN
|
||||||
|
#ifndef NO_ESP32
|
||||||
// If BUTTON_PIN is held down during the startup process,
|
// If BUTTON_PIN is held down during the startup process,
|
||||||
// force the device to go into a SoftAP mode.
|
// force the device to go into a SoftAP mode.
|
||||||
bool forceSoftAP = 0;
|
bool forceSoftAP = 0;
|
||||||
#ifdef BUTTON_PIN
|
|
||||||
#ifndef NO_ESP32
|
|
||||||
pinMode(BUTTON_PIN, INPUT);
|
pinMode(BUTTON_PIN, INPUT);
|
||||||
|
#ifdef BUTTON_NEED_PULLUP
|
||||||
|
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||||
|
#endif
|
||||||
|
|
||||||
// BUTTON_PIN is pulled high by a 12k resistor.
|
// BUTTON_PIN is pulled high by a 12k resistor.
|
||||||
if (!digitalRead(BUTTON_PIN)) {
|
if (!digitalRead(BUTTON_PIN)) {
|
||||||
forceSoftAP = 1;
|
forceSoftAP = 1;
|
||||||
DEBUG_MSG("-------------------- Setting forceSoftAP = 1\n");
|
DEBUG_MSG("Setting forceSoftAP = 1\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -389,6 +395,19 @@ void setup()
|
|||||||
|
|
||||||
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
|
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
|
||||||
|
|
||||||
|
#ifdef GENIEBLOCKS
|
||||||
|
// 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
|
||||||
|
|
||||||
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
||||||
UBloxGPS *ublox = NULL;
|
UBloxGPS *ublox = NULL;
|
||||||
#ifdef GPS_TX_PIN
|
#ifdef GPS_TX_PIN
|
||||||
@@ -426,14 +445,17 @@ void setup()
|
|||||||
|
|
||||||
service.init();
|
service.init();
|
||||||
|
|
||||||
|
// Now that the mesh service is created, create any plugins
|
||||||
|
setupPlugins();
|
||||||
|
|
||||||
// Do this after service.init (because that clears error_code)
|
// Do this after service.init (because that clears error_code)
|
||||||
#ifdef AXP192_SLAVE_ADDRESS
|
#ifdef AXP192_SLAVE_ADDRESS
|
||||||
if(!axp192_found)
|
if (!axp192_found)
|
||||||
recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
|
recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Don't call screen setup until after nodedb is setup (because we need
|
// Don't call screen setup until after nodedb is setup (because we need
|
||||||
// the current region name)
|
// the current region name)
|
||||||
#if defined(ST7735_CS) || defined(HAS_EINK)
|
#if defined(ST7735_CS) || defined(HAS_EINK)
|
||||||
screen->setup();
|
screen->setup();
|
||||||
#else
|
#else
|
||||||
@@ -494,9 +516,17 @@ void setup()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
// Initialize Wifi
|
// Initialize Wifi
|
||||||
initWifi(forceSoftAP);
|
initWifi(forceSoftAP);
|
||||||
|
|
||||||
|
// Start web server thread.
|
||||||
|
webServerThread = new WebServerThread();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Start airtime logger thread.
|
||||||
|
airTime = new AirTime();
|
||||||
|
|
||||||
if (!rIf)
|
if (!rIf)
|
||||||
recordCriticalError(CriticalErrorCode_NoRadio);
|
recordCriticalError(CriticalErrorCode_NoRadio);
|
||||||
else
|
else
|
||||||
@@ -557,7 +587,7 @@ void loop()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: This should go into a thread handled by FreeRTOS.
|
// TODO: This should go into a thread handled by FreeRTOS.
|
||||||
handleWebResponse();
|
// handleWebResponse();
|
||||||
|
|
||||||
service.loop();
|
service.loop();
|
||||||
|
|
||||||
@@ -570,7 +600,4 @@ void loop()
|
|||||||
// We want to sleep as long as possible here - because it saves power
|
// We want to sleep as long as possible here - because it saves power
|
||||||
mainDelay.delay(delayMsec);
|
mainDelay.delay(delayMsec);
|
||||||
// if (didWake) DEBUG_MSG("wake!\n");
|
// if (didWake) DEBUG_MSG("wake!\n");
|
||||||
|
|
||||||
// Handles cleanup for the airtime calculator.
|
|
||||||
airtimeCalculator();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ static int32_t sendOwnerCb()
|
|||||||
currentGeneration = radioGeneration;
|
currentGeneration = radioGeneration;
|
||||||
|
|
||||||
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
|
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
|
||||||
nodeInfoPlugin.sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
|
assert(nodeInfoPlugin);
|
||||||
|
nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
|
||||||
|
|
||||||
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
|
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
|
||||||
}
|
}
|
||||||
@@ -134,7 +135,8 @@ bool MeshService::reloadConfig()
|
|||||||
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
||||||
void MeshService::reloadOwner()
|
void MeshService::reloadOwner()
|
||||||
{
|
{
|
||||||
nodeInfoPlugin.sendOurNodeInfo();
|
assert(nodeInfoPlugin);
|
||||||
|
nodeInfoPlugin->sendOurNodeInfo();
|
||||||
nodeDB.saveToDisk();
|
nodeDB.saveToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,17 +195,40 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
|||||||
assert(node);
|
assert(node);
|
||||||
|
|
||||||
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
|
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
|
||||||
|
assert(positionPlugin && nodeInfoPlugin);
|
||||||
if (node->has_position)
|
if (node->has_position)
|
||||||
positionPlugin.sendOurPosition(dest, wantReplies);
|
positionPlugin->sendOurPosition(dest, wantReplies);
|
||||||
else
|
else
|
||||||
nodeInfoPlugin.sendOurNodeInfo(dest, wantReplies);
|
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NodeInfo *MeshService::refreshMyNodeInfo() {
|
||||||
|
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
// We might not have a position yet for our local node, in that case, at least try to send the time
|
||||||
|
if(!node->has_position) {
|
||||||
|
memset(&node->position, 0, sizeof(node->position));
|
||||||
|
node->has_position = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position &position = node->position;
|
||||||
|
|
||||||
|
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||||
|
position.time = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
|
||||||
|
|
||||||
|
position.battery_level = powerStatus->getBatteryChargePercent();
|
||||||
|
updateBatteryLevel(position.battery_level);
|
||||||
|
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
||||||
{
|
{
|
||||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||||
|
NodeInfo *node = refreshMyNodeInfo();
|
||||||
Position pos = Position_init_default;
|
Position pos = node->position;
|
||||||
|
|
||||||
if (gps->hasLock()) {
|
if (gps->hasLock()) {
|
||||||
if (gps->altitude != 0)
|
if (gps->altitude != 0)
|
||||||
@@ -214,21 +239,16 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
|||||||
else {
|
else {
|
||||||
// The GPS has lost lock, if we are fixed position we should just keep using
|
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||||
// the old position
|
// the old position
|
||||||
if(radioConfig.preferences.fixed_position) {
|
if(!radioConfig.preferences.fixed_position) {
|
||||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
|
||||||
assert(node);
|
|
||||||
assert(node->has_position);
|
|
||||||
pos = node->position;
|
|
||||||
DEBUG_MSG("WARNING: Using fixed position\n");
|
DEBUG_MSG("WARNING: Using fixed position\n");
|
||||||
|
} else {
|
||||||
|
// throw away old position
|
||||||
|
pos.latitude_i = 0;
|
||||||
|
pos.longitude_i = 0;
|
||||||
|
pos.altitude = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos.time = getValidTime(RTCQualityGPS);
|
|
||||||
|
|
||||||
// Include our current battery voltage in our position announcement
|
|
||||||
pos.battery_level = powerStatus->getBatteryChargePercent();
|
|
||||||
updateBatteryLevel(pos.battery_level);
|
|
||||||
|
|
||||||
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
|
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
|
||||||
|
|
||||||
// Update our current position in the local DB
|
// Update our current position in the local DB
|
||||||
@@ -247,7 +267,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
|||||||
currentGeneration = radioGeneration;
|
currentGeneration = radioGeneration;
|
||||||
|
|
||||||
DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies);
|
DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies);
|
||||||
positionPlugin.sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
assert(positionPlugin);
|
||||||
|
positionPlugin->sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ class MeshService
|
|||||||
/// cache
|
/// cache
|
||||||
void sendToMesh(MeshPacket *p);
|
void sendToMesh(MeshPacket *p);
|
||||||
|
|
||||||
|
/// Pull the latest power and time info into my nodeinfo
|
||||||
|
NodeInfo *refreshMyNodeInfo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
|
|
||||||
#include "CryptoEngine.h"
|
#include "CryptoEngine.h"
|
||||||
|
#include "FSCommon.h"
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
@@ -15,11 +16,13 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "meshwifi/meshwifi.h"
|
|
||||||
#include "FSCommon.h"
|
|
||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
#include <pb_encode.h>
|
#include <pb_encode.h>
|
||||||
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
NodeDB nodeDB;
|
NodeDB nodeDB;
|
||||||
|
|
||||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||||
@@ -28,7 +31,7 @@ MyNodeInfo &myNodeInfo = devicestate.my_node;
|
|||||||
RadioConfig &radioConfig = devicestate.radio;
|
RadioConfig &radioConfig = devicestate.radio;
|
||||||
ChannelSettings &channelSettings = radioConfig.channel_settings;
|
ChannelSettings &channelSettings = radioConfig.channel_settings;
|
||||||
|
|
||||||
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
|
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
|
||||||
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
||||||
*/
|
*/
|
||||||
uint32_t radioGeneration;
|
uint32_t radioGeneration;
|
||||||
@@ -41,8 +44,6 @@ DeviceState versions used to be defined in the .proto file but really only this
|
|||||||
#define DEVICESTATE_CUR_VER 11
|
#define DEVICESTATE_CUR_VER 11
|
||||||
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME - move this somewhere else
|
// FIXME - move this somewhere else
|
||||||
extern void getMacAddr(uint8_t *dmac);
|
extern void getMacAddr(uint8_t *dmac);
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ const char *getChannelName()
|
|||||||
static char buf[32];
|
static char buf[32];
|
||||||
|
|
||||||
char suffix;
|
char suffix;
|
||||||
if(channelSettings.psk.size != 1) {
|
if (channelSettings.psk.size != 1) {
|
||||||
// We have a standard PSK, so generate a letter based hash.
|
// We have a standard PSK, so generate a letter based hash.
|
||||||
uint8_t code = 0;
|
uint8_t code = 0;
|
||||||
for (int i = 0; i < activePSKSize; i++)
|
for (int i = 0; i < activePSKSize; i++)
|
||||||
@@ -140,32 +141,40 @@ bool NodeDB::resetRadioConfig()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the old string "Default" to our new short representation
|
// Convert the old string "Default" to our new short representation
|
||||||
if(strcmp(channelSettings.name, "Default") == 0)
|
if (strcmp(channelSettings.name, "Default") == 0)
|
||||||
*channelSettings.name = '\0';
|
*channelSettings.name = '\0';
|
||||||
|
|
||||||
// Convert the short "" representation for Default into a usable string
|
// Convert the short "" representation for Default into a usable string
|
||||||
channelName = channelSettings.name;
|
channelName = channelSettings.name;
|
||||||
if(!*channelName) { // emptystring
|
if (!*channelName) { // emptystring
|
||||||
// Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case
|
// Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case
|
||||||
// the app fucked up and forgot to set channelSettings.name
|
// the app fucked up and forgot to set channelSettings.name
|
||||||
channelName = "Unset";
|
|
||||||
if(channelSettings.bandwidth == 0) switch(channelSettings.modem_config) {
|
if (channelSettings.bandwidth != 0)
|
||||||
|
channelName = "Unset";
|
||||||
|
else
|
||||||
|
switch (channelSettings.modem_config) {
|
||||||
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
|
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
|
||||||
channelName = "Medium"; break;
|
channelName = "Medium";
|
||||||
|
break;
|
||||||
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
|
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
|
||||||
channelName = "ShortFast"; break;
|
channelName = "ShortFast";
|
||||||
|
break;
|
||||||
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
|
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
|
||||||
channelName = "LongAlt"; break;
|
channelName = "LongAlt";
|
||||||
|
break;
|
||||||
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||||
channelName = "LongSlow"; break;
|
channelName = "LongSlow";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
channelName = "Invalid"; break;
|
channelName = "Invalid";
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert any old usage of the defaultpsk into our new short representation.
|
// Convert any old usage of the defaultpsk into our new short representation.
|
||||||
if(channelSettings.psk.size == sizeof(defaultpsk) &&
|
if (channelSettings.psk.size == sizeof(defaultpsk) &&
|
||||||
memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) {
|
memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) {
|
||||||
*channelSettings.psk.bytes = 1;
|
*channelSettings.psk.bytes = 1;
|
||||||
channelSettings.psk.size = 1;
|
channelSettings.psk.size = 1;
|
||||||
}
|
}
|
||||||
@@ -173,10 +182,10 @@ bool NodeDB::resetRadioConfig()
|
|||||||
// Convert the short single byte variants of psk into variant that can be used more generally
|
// Convert the short single byte variants of psk into variant that can be used more generally
|
||||||
memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size);
|
memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size);
|
||||||
activePSKSize = channelSettings.psk.size;
|
activePSKSize = channelSettings.psk.size;
|
||||||
if(activePSKSize == 1) {
|
if (activePSKSize == 1) {
|
||||||
uint8_t pskIndex = activePSK[0];
|
uint8_t pskIndex = activePSK[0];
|
||||||
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
|
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
|
||||||
if(pskIndex == 0)
|
if (pskIndex == 0)
|
||||||
activePSKSize = 0; // Turn off encryption
|
activePSKSize = 0; // Turn off encryption
|
||||||
else {
|
else {
|
||||||
memcpy(activePSK, defaultpsk, sizeof(defaultpsk));
|
memcpy(activePSK, defaultpsk, sizeof(defaultpsk));
|
||||||
@@ -271,12 +280,13 @@ void NodeDB::init()
|
|||||||
myNodeInfo.node_num_bits = sizeof(NodeNum) * 8;
|
myNodeInfo.node_num_bits = sizeof(NodeNum) * 8;
|
||||||
myNodeInfo.packet_id_bits = sizeof(PacketId) * 8;
|
myNodeInfo.packet_id_bits = sizeof(PacketId) * 8;
|
||||||
|
|
||||||
myNodeInfo.error_code = CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash)
|
myNodeInfo.error_code =
|
||||||
|
CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash)
|
||||||
myNodeInfo.error_address = 0;
|
myNodeInfo.error_address = 0;
|
||||||
|
|
||||||
// likewise - we always want the app requirements to come from the running appload
|
// likewise - we always want the app requirements to come from the running appload
|
||||||
myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
|
myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
|
||||||
|
|
||||||
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
||||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||||
pickNewNodeNum();
|
pickNewNodeNum();
|
||||||
|
|||||||
@@ -21,11 +21,17 @@ void PhoneAPI::init()
|
|||||||
observe(&service.fromNumChanged);
|
observe(&service.fromNumChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhoneAPI::~PhoneAPI() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
void PhoneAPI::close() {
|
void PhoneAPI::close() {
|
||||||
unobserve();
|
unobserve();
|
||||||
state = STATE_SEND_NOTHING;
|
state = STATE_SEND_NOTHING;
|
||||||
|
bool oldConnected = isConnected;
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
onConnectionChanged(isConnected);
|
if(oldConnected != isConnected)
|
||||||
|
onConnectionChanged(isConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhoneAPI::checkConnectionTimeout()
|
void PhoneAPI::checkConnectionTimeout()
|
||||||
@@ -128,6 +134,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
|||||||
fromRadioScratch.which_variant = FromRadio_my_info_tag;
|
fromRadioScratch.which_variant = FromRadio_my_info_tag;
|
||||||
fromRadioScratch.variant.my_info = myNodeInfo;
|
fromRadioScratch.variant.my_info = myNodeInfo;
|
||||||
state = STATE_SEND_RADIO;
|
state = STATE_SEND_RADIO;
|
||||||
|
|
||||||
|
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_SEND_RADIO:
|
case STATE_SEND_RADIO:
|
||||||
|
|||||||
@@ -55,12 +55,15 @@ class PhoneAPI
|
|||||||
public:
|
public:
|
||||||
PhoneAPI();
|
PhoneAPI();
|
||||||
|
|
||||||
|
/// Destructor - calls close()
|
||||||
|
virtual ~PhoneAPI();
|
||||||
|
|
||||||
/// Do late init that can't happen at constructor time
|
/// Do late init that can't happen at constructor time
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
|
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
|
||||||
// Unregisters our observer
|
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
|
||||||
void close();
|
virtual void close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a ToRadio protobuf
|
* Handle a ToRadio protobuf
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level
|
#define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level
|
||||||
|
|
||||||
RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi)
|
RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi)
|
||||||
: RadioLibInterface(cs, irq, rst, 0, spi)
|
: RadioLibInterface(cs, irq, rst, RADIOLIB_NC, spi)
|
||||||
{
|
{
|
||||||
// FIXME - we assume devices never get destroyed
|
// FIXME - we assume devices never get destroyed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ class RF95Interface : public RadioLibInterface
|
|||||||
public:
|
public:
|
||||||
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
|
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
|
||||||
|
|
||||||
|
/// Some boards (Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||||
|
bool isIRQPending() { return lora->getPendingIRQ(); }
|
||||||
|
|
||||||
/// Initialise the Driver transport hardware and software.
|
/// Initialise the Driver transport hardware and software.
|
||||||
/// Make sure the Driver is properly configured before calling init().
|
/// Make sure the Driver is properly configured before calling init().
|
||||||
/// \return true if initialisation succeeded.
|
/// \return true if initialisation succeeded.
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
|||||||
|
|
||||||
// Count the packet toward our TX airtime utilization.
|
// Count the packet toward our TX airtime utilization.
|
||||||
// We only count it if it can be added to the TX queue.
|
// We only count it if it can be added to the TX queue.
|
||||||
logAirtime(TX_LOG, xmitMsec);
|
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||||
|
//airTime.logAirtime(TX_LOG, xmitMsec);
|
||||||
|
|
||||||
// We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent
|
// We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent
|
||||||
// in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio
|
// in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio
|
||||||
@@ -216,7 +217,8 @@ void RadioLibInterface::handleReceiveInterrupt()
|
|||||||
size_t length = iface->getPacketLength();
|
size_t length = iface->getPacketLength();
|
||||||
|
|
||||||
xmitMsec = getPacketTime(length);
|
xmitMsec = getPacketTime(length);
|
||||||
logAirtime(RX_ALL_LOG, xmitMsec);
|
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
||||||
|
//airTime.logAirtime(RX_ALL_LOG, xmitMsec);
|
||||||
|
|
||||||
int state = iface->readData(radiobuf, length);
|
int state = iface->readData(radiobuf, length);
|
||||||
if (state != ERR_NONE) {
|
if (state != ERR_NONE) {
|
||||||
@@ -258,7 +260,8 @@ void RadioLibInterface::handleReceiveInterrupt()
|
|||||||
printPacket("Lora RX", mp);
|
printPacket("Lora RX", mp);
|
||||||
|
|
||||||
xmitMsec = getPacketTime(mp);
|
xmitMsec = getPacketTime(mp);
|
||||||
logAirtime(RX_LOG, xmitMsec);
|
airTime->logAirtime(RX_LOG, xmitMsec);
|
||||||
|
//airTime.logAirtime(RX_LOG, xmitMsec);
|
||||||
|
|
||||||
deliverToReceiver(mp);
|
deliverToReceiver(mp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg;
|
|||||||
#define DeviceState_fields &DeviceState_msg
|
#define DeviceState_fields &DeviceState_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define DeviceState_size 6176
|
#define DeviceState_size 6206
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -57,3 +57,4 @@ PB_BIND(ToRadio, ToRadio, 2)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,26 @@ typedef enum _RegionCode {
|
|||||||
RegionCode_TW = 8
|
RegionCode_TW = 8
|
||||||
} RegionCode;
|
} RegionCode;
|
||||||
|
|
||||||
|
typedef enum _ChargeCurrent {
|
||||||
|
ChargeCurrent_MAUnset = 0,
|
||||||
|
ChargeCurrent_MA100 = 1,
|
||||||
|
ChargeCurrent_MA190 = 2,
|
||||||
|
ChargeCurrent_MA280 = 3,
|
||||||
|
ChargeCurrent_MA360 = 4,
|
||||||
|
ChargeCurrent_MA450 = 5,
|
||||||
|
ChargeCurrent_MA550 = 6,
|
||||||
|
ChargeCurrent_MA630 = 7,
|
||||||
|
ChargeCurrent_MA700 = 8,
|
||||||
|
ChargeCurrent_MA780 = 9,
|
||||||
|
ChargeCurrent_MA880 = 10,
|
||||||
|
ChargeCurrent_MA960 = 11,
|
||||||
|
ChargeCurrent_MA1000 = 12,
|
||||||
|
ChargeCurrent_MA1080 = 13,
|
||||||
|
ChargeCurrent_MA1160 = 14,
|
||||||
|
ChargeCurrent_MA1240 = 15,
|
||||||
|
ChargeCurrent_MA1320 = 16
|
||||||
|
} ChargeCurrent;
|
||||||
|
|
||||||
typedef enum _GpsOperation {
|
typedef enum _GpsOperation {
|
||||||
GpsOperation_GpsOpUnset = 0,
|
GpsOperation_GpsOpUnset = 0,
|
||||||
GpsOperation_GpsOpMobile = 2,
|
GpsOperation_GpsOpMobile = 2,
|
||||||
@@ -145,6 +165,7 @@ typedef struct _RadioConfig_UserPreferences {
|
|||||||
char wifi_password[64];
|
char wifi_password[64];
|
||||||
bool wifi_ap_mode;
|
bool wifi_ap_mode;
|
||||||
RegionCode region;
|
RegionCode region;
|
||||||
|
ChargeCurrent charge_current;
|
||||||
LocationSharing location_share;
|
LocationSharing location_share;
|
||||||
GpsOperation gps_operation;
|
GpsOperation gps_operation;
|
||||||
uint32_t gps_update_interval;
|
uint32_t gps_update_interval;
|
||||||
@@ -156,6 +177,11 @@ typedef struct _RadioConfig_UserPreferences {
|
|||||||
bool debug_log_enabled;
|
bool debug_log_enabled;
|
||||||
pb_size_t ignore_incoming_count;
|
pb_size_t ignore_incoming_count;
|
||||||
uint32_t ignore_incoming[3];
|
uint32_t ignore_incoming[3];
|
||||||
|
bool serialplugin_enabled;
|
||||||
|
bool serialplugin_echo;
|
||||||
|
uint32_t serialplugin_rxd;
|
||||||
|
uint32_t serialplugin_txd;
|
||||||
|
uint32_t serialplugin_timeout;
|
||||||
} RadioConfig_UserPreferences;
|
} RadioConfig_UserPreferences;
|
||||||
|
|
||||||
typedef struct _RouteDiscovery {
|
typedef struct _RouteDiscovery {
|
||||||
@@ -265,6 +291,10 @@ typedef struct _ToRadio {
|
|||||||
#define _RegionCode_MAX RegionCode_TW
|
#define _RegionCode_MAX RegionCode_TW
|
||||||
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
|
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
|
||||||
|
|
||||||
|
#define _ChargeCurrent_MIN ChargeCurrent_MAUnset
|
||||||
|
#define _ChargeCurrent_MAX ChargeCurrent_MA1320
|
||||||
|
#define _ChargeCurrent_ARRAYSIZE ((ChargeCurrent)(ChargeCurrent_MA1320+1))
|
||||||
|
|
||||||
#define _GpsOperation_MIN GpsOperation_GpsOpUnset
|
#define _GpsOperation_MIN GpsOperation_GpsOpUnset
|
||||||
#define _GpsOperation_MAX GpsOperation_GpsOpDisabled
|
#define _GpsOperation_MAX GpsOperation_GpsOpDisabled
|
||||||
#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
|
#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
|
||||||
@@ -299,7 +329,7 @@ extern "C" {
|
|||||||
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0}
|
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0}
|
||||||
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
||||||
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0}
|
||||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
||||||
@@ -313,7 +343,7 @@ extern "C" {
|
|||||||
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0}
|
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0}
|
||||||
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
||||||
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0}
|
||||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||||
@@ -371,6 +401,7 @@ extern "C" {
|
|||||||
#define RadioConfig_UserPreferences_wifi_password_tag 13
|
#define RadioConfig_UserPreferences_wifi_password_tag 13
|
||||||
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
|
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
|
||||||
#define RadioConfig_UserPreferences_region_tag 15
|
#define RadioConfig_UserPreferences_region_tag 15
|
||||||
|
#define RadioConfig_UserPreferences_charge_current_tag 16
|
||||||
#define RadioConfig_UserPreferences_location_share_tag 32
|
#define RadioConfig_UserPreferences_location_share_tag 32
|
||||||
#define RadioConfig_UserPreferences_gps_operation_tag 33
|
#define RadioConfig_UserPreferences_gps_operation_tag 33
|
||||||
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
|
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
|
||||||
@@ -381,6 +412,11 @@ extern "C" {
|
|||||||
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
||||||
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
|
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
|
||||||
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
|
#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 RouteDiscovery_route_tag 2
|
#define RouteDiscovery_route_tag 2
|
||||||
#define User_id_tag 1
|
#define User_id_tag 1
|
||||||
#define User_long_name_tag 2
|
#define User_long_name_tag 2
|
||||||
@@ -533,6 +569,7 @@ X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
|
|||||||
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
|
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
|
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
|
||||||
X(a, STATIC, SINGULAR, UENUM, region, 15) \
|
X(a, STATIC, SINGULAR, UENUM, region, 15) \
|
||||||
|
X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \
|
||||||
X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
|
X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
|
||||||
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
|
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
|
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
|
||||||
@@ -542,7 +579,12 @@ X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
|
|||||||
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
|
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
|
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
|
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
|
||||||
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
|
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)
|
||||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||||
#define RadioConfig_UserPreferences_DEFAULT NULL
|
#define RadioConfig_UserPreferences_DEFAULT NULL
|
||||||
|
|
||||||
@@ -654,13 +696,13 @@ extern const pb_msgdesc_t ToRadio_msg;
|
|||||||
#define SubPacket_size 275
|
#define SubPacket_size 275
|
||||||
#define MeshPacket_size 320
|
#define MeshPacket_size 320
|
||||||
#define ChannelSettings_size 95
|
#define ChannelSettings_size 95
|
||||||
#define RadioConfig_size 319
|
#define RadioConfig_size 349
|
||||||
#define RadioConfig_UserPreferences_size 219
|
#define RadioConfig_UserPreferences_size 249
|
||||||
#define NodeInfo_size 132
|
#define NodeInfo_size 132
|
||||||
#define MyNodeInfo_size 106
|
#define MyNodeInfo_size 106
|
||||||
#define LogRecord_size 81
|
#define LogRecord_size 81
|
||||||
#define FromRadio_size 329
|
#define FromRadio_size 358
|
||||||
#define ToRadio_size 323
|
#define ToRadio_size 353
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -18,13 +18,15 @@ typedef enum _PortNum {
|
|||||||
PortNum_NODEINFO_APP = 4,
|
PortNum_NODEINFO_APP = 4,
|
||||||
PortNum_REPLY_APP = 32,
|
PortNum_REPLY_APP = 32,
|
||||||
PortNum_IP_TUNNEL_APP = 33,
|
PortNum_IP_TUNNEL_APP = 33,
|
||||||
PortNum_PRIVATE_APP = 256
|
PortNum_SERIAL_APP = 64,
|
||||||
|
PortNum_PRIVATE_APP = 256,
|
||||||
|
PortNum_ATAK_FORWARDER = 257
|
||||||
} PortNum;
|
} PortNum;
|
||||||
|
|
||||||
/* Helper constants for enums */
|
/* Helper constants for enums */
|
||||||
#define _PortNum_MIN PortNum_UNKNOWN_APP
|
#define _PortNum_MIN PortNum_UNKNOWN_APP
|
||||||
#define _PortNum_MAX PortNum_PRIVATE_APP
|
#define _PortNum_MAX PortNum_ATAK_FORWARDER
|
||||||
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_PRIVATE_APP+1))
|
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_ATAK_FORWARDER+1))
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
46
src/mesh/http/ContentHandler.h
Normal file
46
src/mesh/http/ContentHandler.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer);
|
||||||
|
|
||||||
|
// Declare some handler functions for the various URLs on the server
|
||||||
|
void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleStyleCSS(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleHotspot(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleRoot(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleStaticPost(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleStatic(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleRestart(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handle404(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleFormUpload(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleReport(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
void handleFavicon(HTTPRequest *req, HTTPResponse *res);
|
||||||
|
|
||||||
|
void middlewareSpeedUp240(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
|
||||||
|
void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
|
||||||
|
void middlewareSession(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
|
||||||
|
|
||||||
|
uint32_t getTimeSpeedUp();
|
||||||
|
void setTimeSpeedUp();
|
||||||
|
|
||||||
|
|
||||||
|
// Interface to the PhoneAPI to access the protobufs with messages
|
||||||
|
class HttpAPI : public PhoneAPI
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Nothing here yet
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Nothing here yet
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Nothing here yet
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
14
src/mesh/http/ContentHelper.cpp
Normal file
14
src/mesh/http/ContentHelper.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "mesh/http/ContentHelper.h"
|
||||||
|
//#include <Arduino.h>
|
||||||
|
//#include "main.h"
|
||||||
|
|
||||||
|
void replaceAll(std::string &str, const std::string &from, const std::string &to)
|
||||||
|
{
|
||||||
|
if (from.empty())
|
||||||
|
return;
|
||||||
|
size_t start_pos = 0;
|
||||||
|
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||||
|
str.replace(start_pos, from.length(), to);
|
||||||
|
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/mesh/http/ContentHelper.h
Normal file
8
src/mesh/http/ContentHelper.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define BoolToString(x) ((x) ? "true" : "false")
|
||||||
|
|
||||||
|
|
||||||
|
void replaceAll(std::string &str, const std::string &from, const std::string &to);
|
||||||
|
|
||||||
@@ -2,14 +2,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Steps:
|
This file contains static content.
|
||||||
- Compress the .js file to .js.gz
|
|
||||||
- Convert to hex:
|
|
||||||
http://tomeko.net/online_tools/file_to_hex.php?lang=en
|
|
||||||
- Paste into the array
|
|
||||||
- Note the filesize of your .gz file and write the file
|
|
||||||
size into the length int.
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Length of the binary data
|
// Length of the binary data
|
||||||
231
src/mesh/http/WebServer.cpp
Normal file
231
src/mesh/http/WebServer.cpp
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
#include "mesh/http/WebServer.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
|
#include <HTTPBodyParser.hpp>
|
||||||
|
#include <HTTPMultipartBodyParser.hpp>
|
||||||
|
#include <HTTPURLEncodedBodyParser.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#include <WebServer.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
#include "esp_task_wdt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Persistant Data Storage
|
||||||
|
#include <Preferences.h>
|
||||||
|
Preferences prefs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Including the esp32_https_server library will trigger a compile time error. I've
|
||||||
|
tracked it down to a reoccurrance of this bug:
|
||||||
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824
|
||||||
|
The work around is described here:
|
||||||
|
https://forums.xilinx.com/t5/Embedded-Development-Tools/Error-with-Standard-Libaries-in-Zynq/td-p/450032
|
||||||
|
|
||||||
|
Long story short is we need "#undef str" before including the esp32_https_server.
|
||||||
|
- Jm Casler (jm@casler.org) Oct 2020
|
||||||
|
*/
|
||||||
|
#undef str
|
||||||
|
|
||||||
|
// Includes for the https server
|
||||||
|
// https://github.com/fhessel/esp32_https_server
|
||||||
|
#include <HTTPRequest.hpp>
|
||||||
|
#include <HTTPResponse.hpp>
|
||||||
|
#include <HTTPSServer.hpp>
|
||||||
|
#include <HTTPServer.hpp>
|
||||||
|
#include <SSLCert.hpp>
|
||||||
|
|
||||||
|
// The HTTPS Server comes in a separate namespace. For easier use, include it here.
|
||||||
|
using namespace httpsserver;
|
||||||
|
#include "mesh/http/ContentHandler.h"
|
||||||
|
|
||||||
|
SSLCert *cert;
|
||||||
|
HTTPSServer *secureServer;
|
||||||
|
HTTPServer *insecureServer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool isWebServerReady = 0;
|
||||||
|
bool isCertReady = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void handleWebResponse()
|
||||||
|
{
|
||||||
|
if (isWifiAvailable() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWebServerReady) {
|
||||||
|
// We're going to handle the DNS responder here so it
|
||||||
|
// will be ignored by the NRF boards.
|
||||||
|
handleDNSResponse();
|
||||||
|
|
||||||
|
secureServer->loop();
|
||||||
|
insecureServer->loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Slow down the CPU if we have not received a request within the last few
|
||||||
|
seconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (millis() - getTimeSpeedUp() >= (25 * 1000)) {
|
||||||
|
setCpuFrequencyMhz(80);
|
||||||
|
setTimeSpeedUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void taskCreateCert(void *parameter)
|
||||||
|
{
|
||||||
|
|
||||||
|
prefs.begin("MeshtasticHTTPS", false);
|
||||||
|
|
||||||
|
// Delete the saved certs
|
||||||
|
if (0) {
|
||||||
|
DEBUG_MSG("Deleting any saved SSL keys ...\n");
|
||||||
|
// prefs.clear();
|
||||||
|
prefs.remove("PK");
|
||||||
|
prefs.remove("cert");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pkLen = prefs.getBytesLength("PK");
|
||||||
|
size_t certLen = prefs.getBytesLength("cert");
|
||||||
|
|
||||||
|
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
|
||||||
|
|
||||||
|
if (pkLen && certLen) {
|
||||||
|
DEBUG_MSG("Existing SSL Certificate found!\n");
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Creating the certificate. This may take a while. Please wait...\n");
|
||||||
|
yield();
|
||||||
|
cert = new SSLCert();
|
||||||
|
yield();
|
||||||
|
int createCertResult = createSelfSignedCert(*cert, KEYSIZE_2048, "CN=meshtastic.local,O=Meshtastic,C=US",
|
||||||
|
"20190101000000", "20300101000000");
|
||||||
|
yield();
|
||||||
|
|
||||||
|
if (createCertResult != 0) {
|
||||||
|
DEBUG_MSG("Creating the certificate failed\n");
|
||||||
|
|
||||||
|
// Serial.printf("Creating the certificate failed. Error Code = 0x%02X, check SSLCert.hpp for details",
|
||||||
|
// createCertResult);
|
||||||
|
// while (true)
|
||||||
|
// delay(500);
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Creating the certificate was successful\n");
|
||||||
|
|
||||||
|
DEBUG_MSG("Created Private Key: %d Bytes\n", cert->getPKLength());
|
||||||
|
// for (int i = 0; i < cert->getPKLength(); i++)
|
||||||
|
// Serial.print(cert->getPKData()[i], HEX);
|
||||||
|
// Serial.println();
|
||||||
|
|
||||||
|
DEBUG_MSG("Created Certificate: %d Bytes\n", cert->getCertLength());
|
||||||
|
// for (int i = 0; i < cert->getCertLength(); i++)
|
||||||
|
// Serial.print(cert->getCertData()[i], HEX);
|
||||||
|
// Serial.println();
|
||||||
|
|
||||||
|
prefs.putBytes("PK", (uint8_t *)cert->getPKData(), cert->getPKLength());
|
||||||
|
prefs.putBytes("cert", (uint8_t *)cert->getCertData(), cert->getCertLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isCertReady = 1;
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSSLCert()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (isWifiAvailable() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new process just to handle creating the cert.
|
||||||
|
// This is a workaround for Bug: https://github.com/fhessel/esp32_https_server/issues/48
|
||||||
|
// jm@casler.org (Oct 2020)
|
||||||
|
xTaskCreate(taskCreateCert, /* Task function. */
|
||||||
|
"createCert", /* String with name of task. */
|
||||||
|
16384, /* Stack size in bytes. */
|
||||||
|
NULL, /* Parameter passed as input of the task */
|
||||||
|
16, /* Priority of the task. */
|
||||||
|
NULL); /* Task handle. */
|
||||||
|
|
||||||
|
DEBUG_MSG("Waiting for SSL Cert to be generated.\n");
|
||||||
|
while (!isCertReady) {
|
||||||
|
DEBUG_MSG(".");
|
||||||
|
delay(1000);
|
||||||
|
yield();
|
||||||
|
esp_task_wdt_reset();
|
||||||
|
}
|
||||||
|
DEBUG_MSG("SSL Cert Ready!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
WebServerThread *webServerThread;
|
||||||
|
|
||||||
|
WebServerThread::WebServerThread() : concurrency::OSThread("WebServerThread") {}
|
||||||
|
|
||||||
|
int32_t WebServerThread::runOnce()
|
||||||
|
{
|
||||||
|
// DEBUG_MSG("WebServerThread::runOnce()\n");
|
||||||
|
handleWebResponse();
|
||||||
|
|
||||||
|
// Loop every 5ms.
|
||||||
|
return (5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initWebServer()
|
||||||
|
{
|
||||||
|
DEBUG_MSG("Initializing Web Server ...\n");
|
||||||
|
|
||||||
|
prefs.begin("MeshtasticHTTPS", false);
|
||||||
|
|
||||||
|
size_t pkLen = prefs.getBytesLength("PK");
|
||||||
|
size_t certLen = prefs.getBytesLength("cert");
|
||||||
|
|
||||||
|
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
|
||||||
|
|
||||||
|
if (pkLen && certLen) {
|
||||||
|
|
||||||
|
uint8_t *pkBuffer = new uint8_t[pkLen];
|
||||||
|
prefs.getBytes("PK", pkBuffer, pkLen);
|
||||||
|
|
||||||
|
uint8_t *certBuffer = new uint8_t[certLen];
|
||||||
|
prefs.getBytes("cert", certBuffer, certLen);
|
||||||
|
|
||||||
|
cert = new SSLCert(certBuffer, certLen, pkBuffer, pkLen);
|
||||||
|
|
||||||
|
DEBUG_MSG("Retrieved Private Key: %d Bytes\n", cert->getPKLength());
|
||||||
|
// DEBUG_MSG("Retrieved Private Key: " + String(cert->getPKLength()) + " Bytes");
|
||||||
|
// for (int i = 0; i < cert->getPKLength(); i++)
|
||||||
|
// Serial.print(cert->getPKData()[i], HEX);
|
||||||
|
// Serial.println();
|
||||||
|
|
||||||
|
DEBUG_MSG("Retrieved Certificate: %d Bytes\n", cert->getCertLength());
|
||||||
|
// for (int i = 0; i < cert->getCertLength(); i++)
|
||||||
|
// Serial.print(cert->getCertData()[i], HEX);
|
||||||
|
// Serial.println();
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Web Server started without SSL keys! How did this happen?\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can now use the new certificate to setup our server as usual.
|
||||||
|
secureServer = new HTTPSServer(cert);
|
||||||
|
insecureServer = new HTTPServer();
|
||||||
|
|
||||||
|
registerHandlers(insecureServer, secureServer);
|
||||||
|
|
||||||
|
DEBUG_MSG("Starting Web Servers...\n");
|
||||||
|
secureServer->start();
|
||||||
|
insecureServer->start();
|
||||||
|
if (secureServer->isRunning() && insecureServer->isRunning()) {
|
||||||
|
DEBUG_MSG("HTTP and HTTPS Web Servers Ready! :-) \n");
|
||||||
|
isWebServerReady = 1;
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("HTTP and HTTPS Web Servers Failed! ;-( \n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
26
src/mesh/http/WebServer.h
Normal file
26
src/mesh/http/WebServer.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PhoneAPI.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
void initWebServer();
|
||||||
|
void createSSLCert();
|
||||||
|
|
||||||
|
|
||||||
|
void handleWebResponse();
|
||||||
|
|
||||||
|
|
||||||
|
class WebServerThread : private concurrency::OSThread
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
WebServerThread();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual int32_t runOnce();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern WebServerThread *webServerThread;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
#include "meshwifi.h"
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "WiFiServerAPI.h"
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshwifi/meshhttp.h"
|
#include "mesh/http/WebServer.h"
|
||||||
|
#include "mesh/wifi/WiFiServerAPI.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
|
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
|
||||||
{
|
{
|
||||||
DEBUG_MSG("Incoming connection from %s\n", client.remoteIP().toString().c_str());
|
DEBUG_MSG("Incoming wifi connection\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFiServerAPI::~WiFiServerAPI()
|
WiFiServerAPI::~WiFiServerAPI()
|
||||||
@@ -28,18 +28,19 @@ void WiFiServerAPI::onConnectionChanged(bool connected)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiServerAPI::loop()
|
/// override close to also shutdown the TCP link
|
||||||
|
void WiFiServerAPI::close() {
|
||||||
|
client.stop(); // drop tcp connection
|
||||||
|
StreamAPI::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiFiServerAPI::loop()
|
||||||
{
|
{
|
||||||
if (client.connected()) {
|
if (client.connected()) {
|
||||||
StreamAPI::loop();
|
StreamAPI::loop();
|
||||||
} else if(isConnected) {
|
return true;
|
||||||
// If our API link was up, shut it down
|
} else {
|
||||||
|
return false;
|
||||||
DEBUG_MSG("Client dropped connection, closing API client\n");
|
|
||||||
// Note: we can't call delete here because this object includes other state
|
|
||||||
// besides the stream API. Instead kill it later when we start a new instance
|
|
||||||
// delete this;
|
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,15 +59,25 @@ int32_t WiFiServerPort::runOnce()
|
|||||||
auto client = available();
|
auto client = available();
|
||||||
if (client) {
|
if (client) {
|
||||||
// Close any previous connection (see FIXME in header file)
|
// Close any previous connection (see FIXME in header file)
|
||||||
if (openAPI)
|
if (openAPI) {
|
||||||
|
DEBUG_MSG("Force closing previous TCP connection\n");
|
||||||
delete openAPI;
|
delete openAPI;
|
||||||
|
}
|
||||||
|
|
||||||
openAPI = new WiFiServerAPI(client);
|
openAPI = new WiFiServerAPI(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openAPI) {
|
if (openAPI) {
|
||||||
// Allow idle processing so the API can read from its incoming stream
|
// Allow idle processing so the API can read from its incoming stream
|
||||||
openAPI->loop();
|
if(!openAPI->loop()) {
|
||||||
|
// If our API link was up, shut it down
|
||||||
|
|
||||||
|
DEBUG_MSG("Client dropped connection, closing API client\n");
|
||||||
|
// Note: we can't call delete here because this object includes other state
|
||||||
|
// besides the stream API. Instead kill it later when we start a new instance
|
||||||
|
delete openAPI;
|
||||||
|
openAPI = NULL;
|
||||||
|
}
|
||||||
return 0; // run fast while our API server is running
|
return 0; // run fast while our API server is running
|
||||||
} else
|
} else
|
||||||
return 100; // only check occasionally for incoming connections
|
return 100; // only check occasionally for incoming connections
|
||||||
@@ -18,7 +18,11 @@ class WiFiServerAPI : public StreamAPI
|
|||||||
|
|
||||||
virtual ~WiFiServerAPI();
|
virtual ~WiFiServerAPI();
|
||||||
|
|
||||||
virtual void loop(); // Check for dropped client connections
|
/// @return true if we want to keep running, or false if we are ready to be destroyed
|
||||||
|
virtual bool loop(); // Check for dropped client connections
|
||||||
|
|
||||||
|
/// override close to also shutdown the TCP link
|
||||||
|
virtual void close();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Hookable to find out when connection changes
|
/// Hookable to find out when connection changes
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "PhoneAPI.h"
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
void initWebServer();
|
|
||||||
void createSSLCert();
|
|
||||||
|
|
||||||
void handleNotFound();
|
|
||||||
|
|
||||||
void handleWebResponse();
|
|
||||||
|
|
||||||
void handleJSONChatHistory();
|
|
||||||
|
|
||||||
void notifyWebUI();
|
|
||||||
|
|
||||||
void handleHotspot();
|
|
||||||
|
|
||||||
void handleStyleCSS();
|
|
||||||
void handleRoot();
|
|
||||||
void handleScriptsScriptJS();
|
|
||||||
void handleJSONChatHistoryDummy();
|
|
||||||
|
|
||||||
void replaceAll(std::string& str, const std::string& from, const std::string& to);
|
|
||||||
|
|
||||||
class HttpAPI : public PhoneAPI
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Nothing here yet
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Nothing here yet
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Nothing here yet
|
|
||||||
};
|
|
||||||
@@ -7,13 +7,16 @@
|
|||||||
#include "esp_bt.h"
|
#include "esp_bt.h"
|
||||||
#include "host/util/util.h"
|
#include "host/util/util.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshwifi/meshwifi.h"
|
|
||||||
#include "nimble/NimbleDefs.h"
|
#include "nimble/NimbleDefs.h"
|
||||||
#include "services/gap/ble_svc_gap.h"
|
#include "services/gap/ble_svc_gap.h"
|
||||||
#include "services/gatt/ble_svc_gatt.h"
|
#include "services/gatt/ble_svc_gatt.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool pinShowing;
|
static bool pinShowing;
|
||||||
static uint32_t doublepressed;
|
static uint32_t doublepressed;
|
||||||
|
|
||||||
@@ -545,7 +548,9 @@ void setBluetoothEnable(bool on)
|
|||||||
if (firstTime) {
|
if (firstTime) {
|
||||||
firstTime = 0;
|
firstTime = 0;
|
||||||
} else {
|
} else {
|
||||||
initWifi(0);
|
#ifndef NO_ESP32
|
||||||
|
initWifi(0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -557,7 +562,9 @@ void setBluetoothEnable(bool on)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// shutdown wifi
|
// shutdown wifi
|
||||||
|
#ifndef NO_ESP32
|
||||||
deinitWifi();
|
deinitWifi();
|
||||||
|
#endif
|
||||||
|
|
||||||
// We have to totally teardown our bluetooth objects to prevent leaks
|
// We have to totally teardown our bluetooth objects to prevent leaks
|
||||||
deinitBLE();
|
deinitBLE();
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#include "meshwifi/meshhttp.h"
|
//#include "mesh/wifi/WebServer.h"
|
||||||
#include "meshwifi/meshwifi.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
|
||||||
|
//#include "mesh/wifi/WiFiAPClient.h"
|
||||||
|
|
||||||
void initWifi(bool forceSoftAP) {}
|
void initWifi(bool forceSoftAP) {}
|
||||||
|
|
||||||
@@ -10,7 +14,4 @@ bool isWifiAvailable()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleWebResponse() {}
|
#endif
|
||||||
|
|
||||||
/// Perform idle loop processing required by the wifi layer
|
|
||||||
void loopWifi() {}
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
NodeInfoPlugin nodeInfoPlugin;
|
NodeInfoPlugin *nodeInfoPlugin;
|
||||||
|
|
||||||
bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p)
|
bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,4 +29,4 @@ class NodeInfoPlugin : public ProtobufPlugin<User>
|
|||||||
virtual MeshPacket *allocReply();
|
virtual MeshPacket *allocReply();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NodeInfoPlugin nodeInfoPlugin;
|
extern NodeInfoPlugin *nodeInfoPlugin;
|
||||||
29
src/plugins/Plugins.cpp
Normal file
29
src/plugins/Plugins.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include "plugins/NodeInfoPlugin.h"
|
||||||
|
#include "plugins/PositionPlugin.h"
|
||||||
|
#include "plugins/RemoteHardwarePlugin.h"
|
||||||
|
#include "plugins/ReplyPlugin.h"
|
||||||
|
#include "plugins/SerialPlugin.h"
|
||||||
|
#include "plugins/TextMessagePlugin.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else)
|
||||||
|
*/
|
||||||
|
void setupPlugins()
|
||||||
|
{
|
||||||
|
nodeInfoPlugin = new NodeInfoPlugin();
|
||||||
|
positionPlugin = new PositionPlugin();
|
||||||
|
textMessagePlugin = new TextMessagePlugin();
|
||||||
|
|
||||||
|
// Note: if the rest of meshtastic doesn't need to explicitly use your plugin, you do not need to assign the instance
|
||||||
|
// to a global variable.
|
||||||
|
|
||||||
|
new RemoteHardwarePlugin();
|
||||||
|
new ReplyPlugin();
|
||||||
|
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
// Only run on an esp32 based device.
|
||||||
|
|
||||||
|
new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
6
src/plugins/Plugins.h
Normal file
6
src/plugins/Plugins.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else)
|
||||||
|
*/
|
||||||
|
void setupPlugins();
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
PositionPlugin positionPlugin;
|
PositionPlugin *positionPlugin;
|
||||||
|
|
||||||
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position &p)
|
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position &p)
|
||||||
{
|
{
|
||||||
@@ -29,15 +29,10 @@ bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position
|
|||||||
|
|
||||||
MeshPacket *PositionPlugin::allocReply()
|
MeshPacket *PositionPlugin::allocReply()
|
||||||
{
|
{
|
||||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position
|
||||||
assert(node);
|
|
||||||
assert(node->has_position);
|
assert(node->has_position);
|
||||||
|
|
||||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
return allocDataProtobuf(node->position);
|
||||||
auto position = node->position;
|
|
||||||
position.time = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
|
|
||||||
|
|
||||||
return allocDataProtobuf(position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
|
void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||||
|
|||||||
@@ -30,4 +30,4 @@ class PositionPlugin : public ProtobufPlugin<Position>
|
|||||||
virtual MeshPacket *allocReply();
|
virtual MeshPacket *allocReply();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PositionPlugin positionPlugin;
|
extern PositionPlugin *positionPlugin;
|
||||||
@@ -6,8 +6,6 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
RemoteHardwarePlugin remoteHardwarePlugin;
|
|
||||||
|
|
||||||
#define NUM_GPIOS 64
|
#define NUM_GPIOS 64
|
||||||
|
|
||||||
// Because (FIXME) we currently don't tell API clients status on sent messages
|
// Because (FIXME) we currently don't tell API clients status on sent messages
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
// Create an a static instance of our plugin - this registers with the plugin system
|
|
||||||
ReplyPlugin replyPlugin;
|
|
||||||
|
|
||||||
MeshPacket *ReplyPlugin::allocReply()
|
MeshPacket *ReplyPlugin::allocReply()
|
||||||
{
|
{
|
||||||
assert(currentRequest); // should always be !NULL
|
assert(currentRequest); // should always be !NULL
|
||||||
|
|||||||
194
src/plugins/SerialPlugin.cpp
Normal file
194
src/plugins/SerialPlugin.cpp
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
#include "SerialPlugin.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "RTC.h"
|
||||||
|
#include "Router.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
SerialPlugin
|
||||||
|
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:
|
||||||
|
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.
|
||||||
|
On tbeam, recommend to use:
|
||||||
|
RXD 35
|
||||||
|
TXD 15
|
||||||
|
3) Set serialplugin_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
|
||||||
|
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
|
||||||
|
to your device.
|
||||||
|
|
||||||
|
TODO (in this order):
|
||||||
|
* Define a verbose RX mode to report on mesh and packet infomration.
|
||||||
|
- 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
|
||||||
|
state. Device connected to that pin may see this as "noise".
|
||||||
|
* Will not work on NRF and the Linux device targets.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
SerialPlugin *serialPlugin;
|
||||||
|
SerialPluginRadio *serialPluginRadio;
|
||||||
|
|
||||||
|
SerialPlugin::SerialPlugin() : concurrency::OSThread("SerialPlugin") {}
|
||||||
|
|
||||||
|
char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||||
|
|
||||||
|
int32_t SerialPlugin::runOnce()
|
||||||
|
{
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
|
||||||
|
/*
|
||||||
|
Uncomment the preferences below if you want to use the plugin
|
||||||
|
without having to configure it from the PythonAPI or WebUI.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// radioConfig.preferences.serialplugin_enabled = 1;
|
||||||
|
// radioConfig.preferences.serialplugin_rxd = 35;
|
||||||
|
// radioConfig.preferences.serialplugin_txd = 15;
|
||||||
|
// radioConfig.preferences.serialplugin_timeout = 1000;
|
||||||
|
// radioConfig.preferences.serialplugin_echo = 1;
|
||||||
|
|
||||||
|
if (radioConfig.preferences.serialplugin_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);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Serial2.begin(SERIALPLUGIN_BAUD, SERIAL_8N1, RXD2, TXD2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radioConfig.preferences.serialplugin_timeout) {
|
||||||
|
Serial2.setTimeout(
|
||||||
|
radioConfig.preferences.serialplugin_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.setRxBufferSize(SERIALPLUGIN_RX_BUFFER);
|
||||||
|
|
||||||
|
serialPluginRadio = new SerialPluginRadio();
|
||||||
|
|
||||||
|
firstTime = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
String serialString;
|
||||||
|
|
||||||
|
while (Serial2.available()) {
|
||||||
|
serialString = Serial2.readString();
|
||||||
|
serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
|
||||||
|
|
||||||
|
serialPluginRadio->sendPayload();
|
||||||
|
|
||||||
|
DEBUG_MSG("Received: %s\n", serialStringChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (10);
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Serial Plugin Disabled\n");
|
||||||
|
|
||||||
|
return (INT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshPacket *SerialPluginRadio::allocReply()
|
||||||
|
{
|
||||||
|
|
||||||
|
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||||
|
{
|
||||||
|
MeshPacket *p = allocReply();
|
||||||
|
p->to = dest;
|
||||||
|
p->decoded.want_response = wantReplies;
|
||||||
|
|
||||||
|
p->want_ack = SERIALPLUGIN_ACK;
|
||||||
|
|
||||||
|
p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
|
||||||
|
memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size);
|
||||||
|
|
||||||
|
service.sendToMesh(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||||
|
{
|
||||||
|
#ifndef NO_ESP32
|
||||||
|
|
||||||
|
if (radioConfig.preferences.serialplugin_enabled) {
|
||||||
|
|
||||||
|
auto &p = mp.decoded.data;
|
||||||
|
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||||
|
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||||
|
|
||||||
|
if (mp.from == nodeDB.getNodeNum()) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX
|
||||||
|
* of the serial interface.
|
||||||
|
*/
|
||||||
|
if (radioConfig.preferences.serialplugin_echo) {
|
||||||
|
|
||||||
|
// For some reason, we get the packet back twice when we send out of the radio.
|
||||||
|
// TODO: need to find out why.
|
||||||
|
if (lastRxID != mp.id) {
|
||||||
|
lastRxID = mp.id;
|
||||||
|
// DEBUG_MSG("* * Message came this device\n");
|
||||||
|
// Serial2.println("* * Message came this device");
|
||||||
|
Serial2.printf("%s", p.payload.bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||||
|
// Serial2.println("* * Message came from the mesh");
|
||||||
|
Serial2.printf("%s", p.payload.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Serial Plugin Disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true; // Let others look at this message also if they want
|
||||||
|
}
|
||||||
54
src/plugins/SerialPlugin.h
Normal file
54
src/plugins/SerialPlugin.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SinglePortPlugin.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class SerialPlugin : private concurrency::OSThread
|
||||||
|
{
|
||||||
|
bool firstTime = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SerialPlugin();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int32_t runOnce();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SerialPlugin *serialPlugin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Radio interface for SerialPlugin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SerialPluginRadio : public SinglePortPlugin
|
||||||
|
{
|
||||||
|
uint32_t lastRxID;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here
|
||||||
|
from the main code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||||
|
SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send our payload into the mesh
|
||||||
|
*/
|
||||||
|
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual MeshPacket *allocReply();
|
||||||
|
|
||||||
|
/** Called to handle a particular incoming message
|
||||||
|
|
||||||
|
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||||
|
*/
|
||||||
|
virtual bool handleReceived(const MeshPacket &mp);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SerialPluginRadio *serialPluginRadio;
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
|
|
||||||
TextMessagePlugin textMessagePlugin;
|
TextMessagePlugin *textMessagePlugin;
|
||||||
|
|
||||||
bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
||||||
{
|
{
|
||||||
@@ -18,11 +18,5 @@ bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
|||||||
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
|
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
|
||||||
notifyObservers(&mp);
|
notifyObservers(&mp);
|
||||||
|
|
||||||
// This is going into the wifidev feature branch
|
|
||||||
// Only update the WebUI if WiFi is enabled
|
|
||||||
//#if WiFi_MODE != 0
|
|
||||||
// notifyWebUI();
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
return false; // Let others look at this message also if they want
|
return false; // Let others look at this message also if they want
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ class TextMessagePlugin : public SinglePortPlugin, public Observable<const MeshP
|
|||||||
virtual bool handleReceived(const MeshPacket &mp);
|
virtual bool handleReceived(const MeshPacket &mp);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TextMessagePlugin textMessagePlugin;
|
extern TextMessagePlugin *textMessagePlugin;
|
||||||
82
src/portduino/CrossPlatformCryptoEngine.cpp
Normal file
82
src/portduino/CrossPlatformCryptoEngine.cpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#include "AES.h"
|
||||||
|
#include "CTR.h"
|
||||||
|
#include "CryptoEngine.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
/** A platform independent AES engine implemented using Tiny-AES
|
||||||
|
*/
|
||||||
|
class CrossPlatformCryptoEngine : public CryptoEngine
|
||||||
|
{
|
||||||
|
|
||||||
|
CTRCommon *ctr = NULL;
|
||||||
|
|
||||||
|
/// How many bytes in our key
|
||||||
|
uint8_t keySize = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CrossPlatformCryptoEngine() {}
|
||||||
|
|
||||||
|
~CrossPlatformCryptoEngine() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the key used for encrypt, decrypt.
|
||||||
|
*
|
||||||
|
* As a special case: If all bytes are zero, we assume _no encryption_ and send all data in cleartext.
|
||||||
|
*
|
||||||
|
* @param numBytes must be 16 (AES128), 32 (AES256) or 0 (no crypt)
|
||||||
|
* @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the
|
||||||
|
* provided pointer)
|
||||||
|
*/
|
||||||
|
virtual void setKey(size_t numBytes, uint8_t *bytes)
|
||||||
|
{
|
||||||
|
keySize = numBytes;
|
||||||
|
DEBUG_MSG("Installing AES%d key!\n", numBytes * 8);
|
||||||
|
if (ctr) {
|
||||||
|
delete ctr;
|
||||||
|
ctr = NULL;
|
||||||
|
}
|
||||||
|
if (numBytes != 0) {
|
||||||
|
if (numBytes == 16)
|
||||||
|
ctr = new CTR<AES128>();
|
||||||
|
else
|
||||||
|
ctr = new CTR<AES256>();
|
||||||
|
|
||||||
|
ctr->setKey(bytes, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt a packet
|
||||||
|
*
|
||||||
|
* @param bytes is updated in place
|
||||||
|
*/
|
||||||
|
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
|
||||||
|
{
|
||||||
|
if (keySize != 0) {
|
||||||
|
uint8_t stream_block[16];
|
||||||
|
static uint8_t scratch[MAX_BLOCKSIZE];
|
||||||
|
size_t nc_off = 0;
|
||||||
|
|
||||||
|
// DEBUG_MSG("ESP32 encrypt!\n");
|
||||||
|
initNonce(fromNode, packetNum);
|
||||||
|
assert(numBytes <= MAX_BLOCKSIZE);
|
||||||
|
memcpy(scratch, bytes, numBytes);
|
||||||
|
memset(scratch + numBytes, 0,
|
||||||
|
sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it)
|
||||||
|
|
||||||
|
ctr->setIV(nonce, sizeof(nonce));
|
||||||
|
ctr->setCounterSize(4);
|
||||||
|
ctr->encrypt(bytes, scratch, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
|
||||||
|
{
|
||||||
|
// For CTR, the implementation is the same
|
||||||
|
encrypt(fromNode, packetNum, numBytes, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
CryptoEngine *crypto = new CrossPlatformCryptoEngine();
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
#include "CryptoEngine.h"
|
#include "CryptoEngine.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include <Utility.h>
|
#include "PortduinoGPIO.h"
|
||||||
|
#include "mesh/RF95Interface.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
|
|
||||||
|
#include <Utility.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
// FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class
|
// FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class
|
||||||
|
|
||||||
uint32_t hwId; // fixme move into portduino
|
uint32_t hwId; // fixme move into portduino
|
||||||
@@ -31,7 +35,60 @@ void cpuDeepSleep(uint64_t msecs) {
|
|||||||
notImplemented("cpuDeepSleep");
|
notImplemented("cpuDeepSleep");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME - implement real crypto for linux
|
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
|
||||||
CryptoEngine *crypto = new CryptoEngine();
|
|
||||||
|
|
||||||
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
|
/** Dear pinetab hardware geeks!
|
||||||
|
*
|
||||||
|
* The current pinetab lora module has a slight bug. The ch341 part only provides ISR assertions on edges.
|
||||||
|
* This makes sense because USB interrupts happen through fast/repeated special irq urbs that are constantly
|
||||||
|
* chattering on the USB bus.
|
||||||
|
*
|
||||||
|
* But this isn't sufficient for level triggered ISR sources like the sx127x radios. The common way that seems to
|
||||||
|
* be addressed by cs341 users is to **always** connect the INT# (pin 26 on the ch341f) signal to one of the GPIO signals
|
||||||
|
* on the part. I'd recommend connecting that LORA_DIO0/INT# line to pin 19 (data 4) on the pinetab board. This would
|
||||||
|
* provide an efficent mechanism so that the (kernel) code in the cs341 driver that I've slightly hacked up to see the
|
||||||
|
* current state of LORA_DIO0. Without that access, I can't know if the interrupt is still pending - which would create
|
||||||
|
* race conditions in packet handling.
|
||||||
|
*
|
||||||
|
* My workaround is to poll the status register internally to the sx127x. Which is expensive because it involves a number of
|
||||||
|
* i2c transactions and many trips back and forth between kernel and my userspace app. I think shipping the current version
|
||||||
|
* of the pinetab lora device would be fine because I can poll slowly (because lora is slow). But if you ever have cause to
|
||||||
|
* rev this board. I highly encourage this small change.
|
||||||
|
*
|
||||||
|
* Btw - your little "USB lora dongle" is really neat. I encourage you to sell it, because even non pinetab customers could
|
||||||
|
* use it to easily add lora to rasberry pi, desktop pcs etc...
|
||||||
|
*
|
||||||
|
* Porduino helper class to do this i2c based polling:
|
||||||
|
*/
|
||||||
|
class R595PolledIrqPin : public GPIOPin {
|
||||||
|
public:
|
||||||
|
R595PolledIrqPin() : GPIOPin(LORA_DIO0, "LORA_DIO0") {}
|
||||||
|
|
||||||
|
/// Read the low level hardware for this pin
|
||||||
|
virtual PinStatus readPinHardware()
|
||||||
|
{
|
||||||
|
if(isrPinStatus < 0)
|
||||||
|
return LOW; // No interrupt handler attached, don't bother polling i2c right now
|
||||||
|
else {
|
||||||
|
extern RadioInterface *rIf; // FIXME, temporary hack until we know if we need to keep this
|
||||||
|
|
||||||
|
assert(rIf);
|
||||||
|
RF95Interface *rIf95 = static_cast<RF95Interface *>(rIf);
|
||||||
|
bool p = rIf95->isIRQPending();
|
||||||
|
// log(SysGPIO, LogDebug, "R595PolledIrqPin::readPinHardware(%s, %d, %d)", getName(), getPinNum(), p);
|
||||||
|
return p ? HIGH : LOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||||
|
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
||||||
|
* before running 'arduino' code.
|
||||||
|
*/
|
||||||
|
void portduinoSetup() {
|
||||||
|
printf("Setting up Meshtastic on Porduino...\n");
|
||||||
|
gpioBind(new R595PolledIrqPin());
|
||||||
|
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
|
||||||
|
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 1
|
major = 1
|
||||||
minor = 1
|
minor = 1
|
||||||
build = 30
|
build = 33
|
||||||
|
|||||||
Reference in New Issue
Block a user