mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-16 14:57:41 +00:00
Compare commits
1 Commits
v1.2.48.37
...
v1.2.45.b6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6740548f3 |
13
.github/workflows/main.yml
vendored
13
.github/workflows/main.yml
vendored
@@ -58,19 +58,6 @@ jobs:
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/meshtastic-web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
run: |
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
|
||||
# We now run integration test before other build steps (to quickly see runtime failures)
|
||||
- name: Build for native
|
||||
run: platformio run -e native
|
||||
|
||||
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
@@ -47,19 +47,6 @@ jobs:
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/meshtastic-web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
run: |
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
|
||||
# Will be available in steps.version.outputs.version
|
||||
- name: Get version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,7 +9,7 @@ main/credentials.h
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
.idea
|
||||
.idea/workspace.xml
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
7
.idea/codeStyles/Project.xml
generated
Normal file
7
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<clangFormatSettings>
|
||||
<option name="ENABLED" value="true" />
|
||||
</clangFormatSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
2
.idea/meshtastic-esp32.iml
generated
Normal file
2
.idea/meshtastic-esp32.iml
generated
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/meshtastic-esp32.iml" filepath="$PROJECT_DIR$/.idea/meshtastic-esp32.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/vcs.xml
generated
Normal file
9
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/design" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/proto" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/sdk-nrfxlib" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -2,10 +2,4 @@
|
||||
[](https://open.vscode.dev/meshtastic/Meshtastic-device)
|
||||
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
|
||||
|
||||
Update Instructions
|
||||
|
||||
[For ESP32 devices click here](https://meshtastic.org/docs/getting-started/flashing-esp32)
|
||||
|
||||
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52)
|
||||
|
||||
For developer information and specific building instructions, please see the [developer doccumentation](https://meshtastic.org/docs/developers)
|
||||
|
||||
Binary file not shown.
@@ -6,10 +6,6 @@ VERSION=`bin/buildinfo.py long`
|
||||
|
||||
# Must have a V prefix to trigger github
|
||||
git tag "v${VERSION}"
|
||||
|
||||
# Commented out per https://github.com/meshtastic/Meshtastic-device/issues/947
|
||||
#git push root "v${VERSION}" # push the tag
|
||||
|
||||
git push origin "v${VERSION}" # push the tag
|
||||
git push root "v${VERSION}" # push the tag
|
||||
|
||||
echo "Tag ${VERSION} pushed to github, github actions should now be building the draft release. If it seems good, click to publish it"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
cd proto && ..\nanopb-0.4.4\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\proto *.proto
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
if [%1]==[] (echo "Please specify a platformio NRF target (i.e. rak4631) as the first argument.") else (python3 .\bin\uf2conv.py .\.pio\build\%1\firmware.hex -c -o .\.pio\build\%1\firmware.uf2 -f 0xADA52840)
|
||||
@@ -16,9 +16,9 @@
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_flags": "-DS113",
|
||||
"sd_name": "s113",
|
||||
"sd_version": "7.2.0",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
|
||||
1
data/static/index.html
Normal file
1
data/static/index.html
Normal file
@@ -0,0 +1 @@
|
||||
not yet supported - soon will be included in build
|
||||
BIN
deprecated/icon-18dp.png
Normal file
BIN
deprecated/icon-18dp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 532 B |
1
deprecated/icon-24px.svg
Normal file
1
deprecated/icon-24px.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 5c-3.87 0-7 3.13-7 7h2c0-2.76 2.24-5 5-5s5 2.24 5 5h2c0-3.87-3.13-7-7-7zm1 9.29c.88-.39 1.5-1.26 1.5-2.29 0-1.38-1.12-2.5-2.5-2.5S9.5 10.62 9.5 12c0 1.02.62 1.9 1.5 2.29v3.3L7.59 21 9 22.41l3-3 3 3L16.41 21 13 17.59v-3.3zM12 1C5.93 1 1 5.93 1 12h2c0-4.97 4.03-9 9-9s9 4.03 9 9h2c0-6.07-4.93-11-11-11z"/></svg>
|
||||
|
After Width: | Height: | Size: 442 B |
BIN
deprecated/icon.png
Normal file
BIN
deprecated/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -20,6 +20,4 @@ make
|
||||
|
||||
* todo run hello world on hardware (check for bl604 vs bl602 first)
|
||||
* build/run in the crummy arduino environment
|
||||
* build in platformio
|
||||
|
||||
https://lupyuen.github.io/articles/lorawan2
|
||||
* build in platformio
|
||||
7
geeksville-private/windows-build-instructions.md
Normal file
7
geeksville-private/windows-build-instructions.md
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
* install python
|
||||
* install git (including git-bash)
|
||||
* install platformio
|
||||
* install vscode
|
||||
* install https://sourceforge.net/projects/mingw-w64/ (for windows gcc/g++) - you'll need to add the bin directory to your PATH
|
||||
@@ -16,12 +16,11 @@
|
||||
;default_envs = tlora_v1_3
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = lora-relay-v1 # nrf board
|
||||
;default_envs = t-echo
|
||||
default_envs = t-echo
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = rak4631
|
||||
;default_envs = rak4630
|
||||
default_envs = meshtastic-diy-v1
|
||||
|
||||
[common]
|
||||
; common is not currently used
|
||||
@@ -69,11 +68,11 @@ debug_tool = jlink
|
||||
|
||||
lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
|
||||
https://github.com/meshtastic/OneButton.git#3bcba9492d01e2a8a86f46700ab16f96dd2cf1f5 ; OneButton library for non-blocking button debounce
|
||||
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
|
||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||
https://github.com/meshtastic/arduino-fsm.git
|
||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
||||
https://github.com/meshtastic/RadioLib.git#80ed10d689a0568782c5bd152906b0f97d2bce93
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
|
||||
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||
@@ -111,8 +110,6 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp32_https_server.git
|
||||
adafruit/DHT sensor library@^1.4.1
|
||||
adafruit/Adafruit Unified Sensor@^1.1.4
|
||||
paulstoffregen/OneWire@^2.3.5
|
||||
robtillaart/DS18B20@^0.1.11
|
||||
# Hmm - this doesn't work yet
|
||||
# board_build.ldscript = linker/esp32.extram.bss.ld
|
||||
lib_ignore = segger_rtt
|
||||
@@ -193,15 +190,6 @@ board = ttgo-lora32-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V2_1_16
|
||||
|
||||
; Meshtastic DIY v1 by Nano VHF Schematic based on ESP32-WROOM-32 (38 pins) devkit & EBYTE E22 SX1262/SX1268 module
|
||||
[env:meshtastic-diy-v1]
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-D DIY_V1
|
||||
-D EBYTE_E22
|
||||
|
||||
; The Heltec Cubecell plus
|
||||
; IMPORTANT NOTE: This target doesn't yet work and probably won't ever work. I'm keeping it around for now.
|
||||
; For more details see my post in the forum.
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 5a556ee4a9...f5b3d0643b
1
src/.gitignore
vendored
Normal file
1
src/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
main.ino.cpp
|
||||
128
src/GPSStatus.h
128
src/GPSStatus.h
@@ -1,11 +1,8 @@
|
||||
#pragma once
|
||||
#include "Status.h"
|
||||
#include "configuration.h"
|
||||
#include "NodeDB.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
extern NodeDB nodeDB;
|
||||
|
||||
namespace meshtastic
|
||||
{
|
||||
|
||||
@@ -19,39 +16,28 @@ class GPSStatus : public Status
|
||||
|
||||
bool hasLock = false; // default to false, until we complete our first read
|
||||
bool isConnected = false; // Do we have a GPS we are talking to
|
||||
|
||||
Position p = Position_init_default;
|
||||
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
|
||||
int32_t altitude = 0;
|
||||
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
|
||||
// scaling before use)
|
||||
uint32_t heading = 0;
|
||||
uint32_t numSatellites = 0;
|
||||
|
||||
public:
|
||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||
|
||||
// proposed for deprecation
|
||||
GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
|
||||
uint32_t heading, uint32_t numSatellites)
|
||||
: Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
this->isConnected = isConnected;
|
||||
|
||||
this->p.latitude_i = latitude;
|
||||
this->p.longitude_i = longitude;
|
||||
this->p.altitude = altitude;
|
||||
this->p.PDOP = dop;
|
||||
this->p.ground_track = heading;
|
||||
this->p.sats_in_view = numSatellites;
|
||||
this->latitude = latitude;
|
||||
this->longitude = longitude;
|
||||
this->altitude = altitude;
|
||||
this->dop = dop;
|
||||
this->heading = heading;
|
||||
this->numSatellites = numSatellites;
|
||||
}
|
||||
|
||||
// preferred method
|
||||
GPSStatus(bool hasLock, bool isConnected, Position pos)
|
||||
: Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
this->isConnected = isConnected;
|
||||
|
||||
// all-in-one struct copy
|
||||
this->p = pos;
|
||||
}
|
||||
|
||||
GPSStatus(const GPSStatus &);
|
||||
GPSStatus &operator=(const GPSStatus &);
|
||||
|
||||
@@ -61,85 +47,45 @@ class GPSStatus : public Status
|
||||
|
||||
bool getIsConnected() const { return isConnected; }
|
||||
|
||||
int32_t getLatitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
DEBUG_MSG("WARNING: Using fixed latitude\n");
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.latitude_i;
|
||||
} else {
|
||||
return p.latitude_i;
|
||||
}
|
||||
}
|
||||
int32_t getLatitude() const { return latitude; }
|
||||
|
||||
int32_t getLongitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
DEBUG_MSG("WARNING: Using fixed longitude\n");
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.longitude_i;
|
||||
} else {
|
||||
return p.longitude_i;
|
||||
}
|
||||
}
|
||||
int32_t getLongitude() const { return longitude; }
|
||||
|
||||
int32_t getAltitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
DEBUG_MSG("WARNING: Using fixed altitude\n");
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
return node->position.altitude;
|
||||
} else {
|
||||
return p.altitude;
|
||||
}
|
||||
}
|
||||
int32_t getAltitude() const { return altitude; }
|
||||
|
||||
uint32_t getDOP() const { return p.PDOP; }
|
||||
uint32_t getDOP() const { return dop; }
|
||||
|
||||
uint32_t getHeading() const { return p.ground_track; }
|
||||
uint32_t getHeading() const { return heading; }
|
||||
|
||||
uint32_t getNumSatellites() const { return p.sats_in_view; }
|
||||
uint32_t getNumSatellites() const { return numSatellites; }
|
||||
|
||||
bool matches(const GPSStatus *newStatus) const
|
||||
{
|
||||
#if GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n",
|
||||
newStatus->p.pos_timestamp, p.pos_timestamp);
|
||||
#endif
|
||||
return (newStatus->hasLock != hasLock ||
|
||||
newStatus->isConnected != isConnected ||
|
||||
newStatus->p.latitude_i != p.latitude_i ||
|
||||
newStatus->p.longitude_i != p.longitude_i ||
|
||||
newStatus->p.altitude != p.altitude ||
|
||||
newStatus->p.altitude_hae != p.altitude_hae ||
|
||||
newStatus->p.PDOP != p.PDOP ||
|
||||
newStatus->p.ground_track != p.ground_track ||
|
||||
newStatus->p.sats_in_view != p.sats_in_view);
|
||||
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->latitude != latitude ||
|
||||
newStatus->longitude != longitude || newStatus->altitude != altitude || newStatus->dop != dop ||
|
||||
newStatus->heading != heading || newStatus->numSatellites != numSatellites);
|
||||
}
|
||||
|
||||
int updateStatus(const GPSStatus *newStatus)
|
||||
{
|
||||
// Only update the status if values have actually changed
|
||||
bool isDirty = matches(newStatus);
|
||||
|
||||
if (isDirty && p.pos_timestamp &&
|
||||
(newStatus->p.pos_timestamp == p.pos_timestamp)) {
|
||||
// We can NEVER be in two locations at the same time! (also PR #886)
|
||||
DEBUG_MSG("BUG!! positional timestamp unchanged from prev solution\n");
|
||||
bool isDirty;
|
||||
{
|
||||
isDirty = matches(newStatus);
|
||||
initialized = true;
|
||||
hasLock = newStatus->hasLock;
|
||||
isConnected = newStatus->isConnected;
|
||||
latitude = newStatus->latitude;
|
||||
longitude = newStatus->longitude;
|
||||
altitude = newStatus->altitude;
|
||||
dop = newStatus->dop;
|
||||
heading = newStatus->heading;
|
||||
numSatellites = newStatus->numSatellites;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
hasLock = newStatus->hasLock;
|
||||
isConnected = newStatus->isConnected;
|
||||
|
||||
p = newStatus->p;
|
||||
|
||||
if (isDirty) {
|
||||
if (hasLock) {
|
||||
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
||||
DEBUG_MSG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, sats=%d\n",
|
||||
p.pos_timestamp,
|
||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7,
|
||||
p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||
p.sats_in_view);
|
||||
} else
|
||||
if (hasLock)
|
||||
DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f, heading=%f, sats=%d\n", latitude * 1e-7, longitude * 1e-7,
|
||||
altitude, dop * 1e-2, heading * 1e-5, numSatellites);
|
||||
else
|
||||
DEBUG_MSG("No GPS lock\n");
|
||||
onNewStatus.notifyObservers(this);
|
||||
}
|
||||
|
||||
@@ -192,7 +192,6 @@ bool Power::setup()
|
||||
found = analogInit();
|
||||
}
|
||||
enabled = found;
|
||||
low_voltage_counter = 0;
|
||||
|
||||
return found;
|
||||
}
|
||||
@@ -239,24 +238,9 @@ void Power::readPowerStatus()
|
||||
powerStatus.getIsCharging(), powerStatus.getBatteryVoltageMv(), powerStatus.getBatteryChargePercent());
|
||||
newStatus.notifyObservers(&powerStatus);
|
||||
|
||||
|
||||
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
|
||||
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
|
||||
#ifdef NRF52_SERIES
|
||||
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB()){
|
||||
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS){
|
||||
low_voltage_counter++;
|
||||
if (low_voltage_counter>3)
|
||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||
} else {
|
||||
low_voltage_counter = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// If we have a battery at all and it is less than 10% full, force deep sleep
|
||||
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
|
||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||
#endif
|
||||
} else {
|
||||
// No power sensing on this board - tell everyone else we have no idea what is happening
|
||||
const PowerStatus powerStatus = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
/// Should we behave as if we have AC power now?
|
||||
static bool isPowered()
|
||||
{
|
||||
// Completely circumvents the battery / power sensing logic and assumes constant power source
|
||||
if (radioConfig.preferences.is_always_powered) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isRouter = radioConfig.preferences.is_router;
|
||||
|
||||
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
|
||||
|
||||
@@ -188,11 +188,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_E22 // Not really an E22 but TTGO seems to be trying to clone that
|
||||
#define SX1262_CS RF95_NSS // FIXME - we really should define LORA_CS instead
|
||||
#define SX1262_DIO1 LORA_DIO1
|
||||
#define SX1262_BUSY LORA_DIO2
|
||||
#define SX1262_RESET LORA_RESET
|
||||
#define SX1262_E22 // Not really an E22 but TTGO seems to be trying to clone that
|
||||
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
|
||||
// code)
|
||||
#endif
|
||||
@@ -226,52 +226,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define GPS_RX_PIN 12
|
||||
#define GPS_TX_PIN 15
|
||||
|
||||
#elif defined(DIY_V1)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_DIY_V1
|
||||
|
||||
// For OLED LCD
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
|
||||
// GPS
|
||||
#undef GPS_RX_PIN
|
||||
#define GPS_RX_PIN 15
|
||||
//#undef GPS_TX_PIN
|
||||
//#define GPS_TX_PIN 12 // not connected
|
||||
|
||||
#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam
|
||||
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262/SX1268 module
|
||||
#define LORA_RESET 23 // RST for SX1276, and for SX1262/SX1268
|
||||
#define LORA_DIO1 33 // IRQ for SX1262/SX1268
|
||||
#define LORA_DIO2 32 // BUSY for SX1262/SX1268
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS 18
|
||||
|
||||
// supported modules list
|
||||
#define USE_SX1262
|
||||
#define USE_SX1268
|
||||
#define USE_LLCC68
|
||||
|
||||
// common pinouts for SX126X modules
|
||||
#define SX126X_CS 18 // NSS for SX126X
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_RXEN 14
|
||||
#define SX126X_TXEN 13
|
||||
|
||||
#ifdef EBYTE_E22
|
||||
// Internally the TTGO module hooks the SX126x-DIO2 in to control the TX/RX switch
|
||||
// (which is the default for the sx1262interface code)
|
||||
#define SX126X_E22
|
||||
#endif
|
||||
|
||||
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
|
||||
|
||||
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
|
||||
@@ -327,8 +281,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 37
|
||||
|
||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 15
|
||||
|
||||
@@ -510,11 +462,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX126X_CS 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
// HOPE RFM90 does not have a TCXO therefore not SX126X_E22
|
||||
#define SX1262_CS 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
|
||||
#define SX1262_DIO1 LORA_DIO1
|
||||
#define SX1262_BUSY LORA_DIO2
|
||||
#define SX1262_RESET LORA_RESET
|
||||
// HOPE RFM90 does not have a TCXO therefore not SX1262_E22
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -80,8 +80,6 @@ GPS::~GPS()
|
||||
notifyDeepSleepObserver.unobserve();
|
||||
}
|
||||
|
||||
bool GPS::hasLock() { return hasValidLocation; }
|
||||
|
||||
// Allow defining the polarity of the WAKE output. default is active high
|
||||
#ifndef GPS_WAKE_ACTIVE
|
||||
#define GPS_WAKE_ACTIVE 1
|
||||
@@ -202,13 +200,11 @@ void GPS::publishUpdate()
|
||||
if (shouldPublish) {
|
||||
shouldPublish = false;
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 2 = publish)
|
||||
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n",
|
||||
p.pos_timestamp, hasValidLocation, hasLock());
|
||||
DEBUG_MSG("publishing GPS lock=%d\n", hasLock());
|
||||
|
||||
// Notify any status instances that are observing us
|
||||
const meshtastic::GPSStatus status =
|
||||
meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
|
||||
meshtastic::GPSStatus(hasLock(), isConnected(), latitude, longitude, altitude, dop, heading, numSatellites);
|
||||
newStatus.notifyObservers(&status);
|
||||
}
|
||||
}
|
||||
@@ -246,7 +242,6 @@ int32_t GPS::runOnce()
|
||||
|
||||
bool gotLoc = lookForLocation();
|
||||
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
|
||||
DEBUG_MSG("hasValidLocation RISING EDGE\n");
|
||||
hasValidLocation = true;
|
||||
shouldPublish = true;
|
||||
}
|
||||
@@ -263,10 +258,6 @@ int32_t GPS::runOnce()
|
||||
|
||||
if (tooLong) {
|
||||
// we didn't get a location during this ack window, therefore declare loss of lock
|
||||
if (hasValidLocation) {
|
||||
DEBUG_MSG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc);
|
||||
}
|
||||
p = Position_init_default;
|
||||
hasValidLocation = false;
|
||||
}
|
||||
|
||||
@@ -334,11 +325,6 @@ GPS *createGps()
|
||||
#ifdef NO_GPS
|
||||
return nullptr;
|
||||
#else
|
||||
#ifdef GPS_ALTITUDE_HAE
|
||||
DEBUG_MSG("Using HAE altitude model\n");
|
||||
#else
|
||||
DEBUG_MSG("Using MSL altitude model\n");
|
||||
#endif
|
||||
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
||||
#ifdef GPS_TX_PIN
|
||||
// Init GPS - first try ublox
|
||||
|
||||
@@ -17,10 +17,6 @@ class GPS : private concurrency::OSThread
|
||||
private:
|
||||
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
|
||||
|
||||
/**
|
||||
* hasValidLocation - indicates that the position variables contain a complete
|
||||
* GPS location, valid and fresh (< gps_update_interval + gps_attempt_time)
|
||||
*/
|
||||
bool hasValidLocation = false; // default to false, until we complete our first read
|
||||
|
||||
bool isAwake = false; // true if we want a location right now
|
||||
@@ -43,7 +39,11 @@ class GPS : private concurrency::OSThread
|
||||
/** If !0 we will attempt to connect to the GPS over I2C */
|
||||
static uint8_t i2cAddress;
|
||||
|
||||
Position p = Position_init_default;
|
||||
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
|
||||
int32_t altitude = 0;
|
||||
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
|
||||
// scaling before use)
|
||||
uint32_t heading = 0; // Heading of motion, in degrees * 10^-5
|
||||
|
||||
GPS() : concurrency::OSThread("GPS") {}
|
||||
|
||||
@@ -57,8 +57,8 @@ class GPS : private concurrency::OSThread
|
||||
*/
|
||||
virtual bool setup();
|
||||
|
||||
/// Returns true if we have acquired GPS lock.
|
||||
virtual bool hasLock();
|
||||
/// Returns ture if we have acquired GPS lock.
|
||||
bool hasLock() const { return hasValidLocation; }
|
||||
|
||||
/// Return true if we are connected to a GPS
|
||||
bool isConnected() const { return hasGPS; }
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
#include "GeoCoord.h"
|
||||
|
||||
GeoCoord::GeoCoord() {
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
GeoCoord::GeoCoord (int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _longitude(lon), _altitude(alt) {
|
||||
GeoCoord::setCoords();
|
||||
}
|
||||
|
||||
GeoCoord::GeoCoord (float lat, float lon, int32_t alt) : _altitude(alt) {
|
||||
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
|
||||
_latitude = int32_t(lat * 1e+7);
|
||||
_longitude = int32_t(lon * 1e+7);
|
||||
GeoCoord::setCoords();
|
||||
}
|
||||
|
||||
GeoCoord::GeoCoord(double lat, double lon, int32_t alt): _altitude(alt) {
|
||||
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
|
||||
_latitude = int32_t(lat * 1e+7);
|
||||
_longitude = int32_t(lon * 1e+7);
|
||||
GeoCoord::setCoords();
|
||||
}
|
||||
|
||||
// Initialize all the coordinate systems
|
||||
void GeoCoord::setCoords() {
|
||||
double lat = _latitude * 1e-7;
|
||||
double lon = _longitude * 1e-7;
|
||||
GeoCoord::latLongToDMS(lat, lon, _dms);
|
||||
GeoCoord::latLongToUTM(lat, lon, _utm);
|
||||
GeoCoord::latLongToMGRS(lat, lon, _mgrs);
|
||||
GeoCoord::latLongToOSGR(lat, lon, _osgr);
|
||||
GeoCoord::latLongToOLC(lat, lon, _olc);
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt) {
|
||||
// If marked dirty or new coordiantes
|
||||
if(_dirty || _latitude != lat || _longitude != lon || _altitude != alt) {
|
||||
_dirty = true;
|
||||
_latitude = lat;
|
||||
_longitude = lon;
|
||||
_altitude = alt;
|
||||
setCoords();
|
||||
}
|
||||
}
|
||||
|
||||
void GeoCoord::updateCoords(const double lat, const double lon, const int32_t alt) {
|
||||
int32_t iLat = lat * 1e+7;
|
||||
int32_t iLon = lon * 1e+7;
|
||||
// If marked dirty or new coordiantes
|
||||
if(_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
||||
_dirty = true;
|
||||
_latitude = iLat;
|
||||
_longitude = iLon;
|
||||
_altitude = alt;
|
||||
setCoords();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt) {
|
||||
int32_t iLat = lat * 1e+7;
|
||||
int32_t iLon = lon * 1e+7;
|
||||
// If marked dirty or new coordiantes
|
||||
if(_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
||||
_dirty = true;
|
||||
_latitude = iLat;
|
||||
_longitude = iLon;
|
||||
_altitude = alt;
|
||||
setCoords();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts lat long coordinates from decimal degrees to degrees minutes seconds format.
|
||||
* DD°MM'SS"C DDD°MM'SS"C
|
||||
*/
|
||||
void GeoCoord::latLongToDMS(const double lat, const double lon, DMS &dms) {
|
||||
if (lat < 0) dms.latCP = 'S';
|
||||
else dms.latCP = 'N';
|
||||
|
||||
double latDeg = lat;
|
||||
|
||||
if (lat < 0)
|
||||
latDeg = latDeg * -1;
|
||||
|
||||
dms.latDeg = floor(latDeg);
|
||||
double latMin = (latDeg - dms.latDeg) * 60;
|
||||
dms.latMin = floor(latMin);
|
||||
dms.latSec = (latMin - dms.latMin) * 60;
|
||||
|
||||
if (lon < 0) dms.lonCP = 'W';
|
||||
else dms.lonCP = 'E';
|
||||
|
||||
double lonDeg = lon;
|
||||
|
||||
if (lon < 0)
|
||||
lonDeg = lonDeg * -1;
|
||||
|
||||
dms.lonDeg = floor(lonDeg);
|
||||
double lonMin = (lonDeg - dms.lonDeg) * 60;
|
||||
dms.lonMin = floor(lonMin);
|
||||
dms.lonSec = (lonMin - dms.lonMin) * 60;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts lat long coordinates to UTM.
|
||||
* based on this: https://github.com/walvok/LatLonToUTM/blob/master/latlon_utm.ino
|
||||
*/
|
||||
void GeoCoord::latLongToUTM(const double lat, const double lon, UTM &utm) {
|
||||
|
||||
const std::string latBands = "CDEFGHJKLMNPQRSTUVWXX";
|
||||
utm.zone = int((lon + 180)/6 + 1);
|
||||
utm.band = latBands[int(lat/8 + 10)];
|
||||
double a = 6378137; // WGS84 - equatorial radius
|
||||
double k0 = 0.9996; // UTM point scale on the central meridian
|
||||
double eccSquared = 0.00669438; // eccentricity squared
|
||||
double lonTemp = (lon + 180) - int((lon + 180)/360) * 360 - 180; //Make sure the longitude is between -180.00 .. 179.9
|
||||
double latRad = toRadians(lat);
|
||||
double lonRad = toRadians(lonTemp);
|
||||
|
||||
// Special Zones for Norway and Svalbard
|
||||
if( lat >= 56.0 && lat < 64.0 && lonTemp >= 3.0 && lonTemp < 12.0 ) // Norway
|
||||
utm.zone = 32;
|
||||
if( lat >= 72.0 && lat < 84.0 ) { // Svalbard
|
||||
if ( lonTemp >= 0.0 && lonTemp < 9.0 ) utm.zone = 31;
|
||||
else if( lonTemp >= 9.0 && lonTemp < 21.0 ) utm.zone = 33;
|
||||
else if( lonTemp >= 21.0 && lonTemp < 33.0 ) utm.zone = 35;
|
||||
else if( lonTemp >= 33.0 && lonTemp < 42.0 ) utm.zone = 37;
|
||||
}
|
||||
|
||||
double lonOrigin = (utm.zone - 1)*6 - 180 + 3; // puts origin in middle of zone
|
||||
double lonOriginRad = toRadians(lonOrigin);
|
||||
double eccPrimeSquared = (eccSquared)/(1 - eccSquared);
|
||||
double N = a/sqrt(1 - eccSquared*sin(latRad)*sin(latRad));
|
||||
double T = tan(latRad)*tan(latRad);
|
||||
double C = eccPrimeSquared*cos(latRad)*cos(latRad);
|
||||
double A = cos(latRad)*(lonRad - lonOriginRad);
|
||||
double M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256)*latRad
|
||||
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*latRad)
|
||||
+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*latRad)
|
||||
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*latRad));
|
||||
utm.easting = (double)(k0*N*(A+(1-T+C)*pow(A, 3)/6 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
|
||||
+ 500000.0);
|
||||
utm.northing = (double)(k0*(M+N*tan(latRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
|
||||
+ (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
|
||||
|
||||
if(lat < 0)
|
||||
utm.northing += 10000000.0; //10000000 meter offset for southern hemisphere
|
||||
}
|
||||
|
||||
// Converts lat long coordinates to an MGRS.
|
||||
void GeoCoord::latLongToMGRS(const double lat, const double lon, MGRS &mgrs) {
|
||||
const std::string e100kLetters[3] = { "ABCDEFGH", "JKLMNPQR", "STUVWXYZ" };
|
||||
const std::string n100kLetters[2] = { "ABCDEFGHJKLMNPQRSTUV", "FGHJKLMNPQRSTUVABCDE" };
|
||||
UTM utm;
|
||||
latLongToUTM(lat, lon, utm);
|
||||
mgrs.zone = utm.zone;
|
||||
mgrs.band = utm.band;
|
||||
double col = floor(utm.easting / 100000);
|
||||
mgrs.east100k = e100kLetters[(mgrs.zone - 1) % 3][col - 1];
|
||||
double row = (int32_t)floor(utm.northing / 100000.0) % 20;
|
||||
mgrs.north100k = n100kLetters[(mgrs.zone-1)%2][row];
|
||||
mgrs.easting = (int32_t)utm.easting % 100000;
|
||||
mgrs.northing = (int32_t)utm.northing % 100000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts lat long coordinates to Ordnance Survey Grid Reference (UK National Grid Ref).
|
||||
* Based on: https://www.movable-type.co.uk/scripts/latlong-os-gridref.html
|
||||
*/
|
||||
void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) {
|
||||
char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR
|
||||
double a = 6377563.396; // Airy 1830 semi-major axis
|
||||
double b = 6356256.909; // Airy 1830 semi-minor axis
|
||||
double f0 = 0.9996012717; // National Grid point scale factor on the central meridian
|
||||
double phi0 = toRadians(49);
|
||||
double lambda0 = toRadians(-2);
|
||||
double n0 = -100000;
|
||||
double e0 = 400000;
|
||||
double e2 = 1 - (b*b)/(a*a); // eccentricity squared
|
||||
double n = (a - b)/(a + b);
|
||||
|
||||
double osgb_Latitude;
|
||||
double osgb_Longitude;
|
||||
convertWGS84ToOSGB36(lat, lon, osgb_Latitude, osgb_Longitude);
|
||||
double phi = osgb_Latitude; // already in radians
|
||||
double lambda = osgb_Longitude; // already in radians
|
||||
double v = a * f0 / sqrt(1 - e2 * sin(phi) * sin(phi));
|
||||
double rho = a * f0 * (1 - e2) / pow(1 - e2 * sin(phi) * sin(phi), 1.5);
|
||||
double eta2 = v / rho - 1;
|
||||
double mA = (1 + n + (5/4)*n*n + (5/4)*n*n*n) * (phi - phi0);
|
||||
double mB = (3*n + 3*n*n + (21/8)*n*n*n) * sin(phi - phi0) * cos(phi + phi0);
|
||||
// loss of precision in mC & mD due to floating point rounding can cause innaccuracy of northing by a few meters
|
||||
double mC = (15/8*n*n + 15/8*n*n*n) * sin(2*(phi - phi0)) * cos(2*(phi + phi0));
|
||||
double mD = (35/24)*n*n*n * sin(3*(phi - phi0)) * cos(3*(phi + phi0));
|
||||
double m = b*f0*(mA - mB + mC - mD);
|
||||
|
||||
double cos3Phi = cos(phi)*cos(phi)*cos(phi);
|
||||
double cos5Phi = cos3Phi*cos(phi)*cos(phi);
|
||||
double tan2Phi = tan(phi)*tan(phi);
|
||||
double tan4Phi = tan2Phi*tan2Phi;
|
||||
double I = m + n0;
|
||||
double II = (v/2)*sin(phi)*cos(phi);
|
||||
double III = (v/24)*sin(phi)*cos3Phi*(5 - tan2Phi + 9*eta2);
|
||||
double IIIA = (v/720)*sin(phi)*cos5Phi*(61 - 58*tan2Phi + tan4Phi);
|
||||
double IV = v*cos(phi);
|
||||
double V = (v/6)*cos3Phi*(v/rho - tan2Phi);
|
||||
double VI = (v/120)*cos5Phi*(5 - 18*tan2Phi + tan4Phi + 14*eta2 - 58*tan2Phi*eta2);
|
||||
|
||||
double deltaLambda = lambda - lambda0;
|
||||
double deltaLambda2 = deltaLambda*deltaLambda;
|
||||
double northing = I + II*deltaLambda2 + III*deltaLambda2*deltaLambda2 + IIIA*deltaLambda2*deltaLambda2*deltaLambda2;
|
||||
double easting = e0 + IV*deltaLambda + V*deltaLambda2*deltaLambda + VI*deltaLambda2*deltaLambda2*deltaLambda;
|
||||
|
||||
if (easting < 0 || easting > 700000 || northing < 0 || northing > 1300000) // Check if out of boundaries
|
||||
osgr = { 'I', 'I', 0, 0 };
|
||||
else {
|
||||
uint32_t e100k = floor(easting / 100000);
|
||||
uint32_t n100k = floor(northing / 100000);
|
||||
int8_t l1 = (19 - n100k) - (19 - n100k) % 5 + floor((e100k + 10) / 5);
|
||||
int8_t l2 = (19 - n100k) * 5 % 25 + e100k % 5;
|
||||
osgr.e100k = letter[l1];
|
||||
osgr.n100k = letter[l2];
|
||||
osgr.easting = floor((int)easting % 100000);
|
||||
osgr.northing = floor((int)northing % 100000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts lat long coordinates to Open Location Code.
|
||||
* Based on: https://github.com/google/open-location-code/blob/main/c/src/olc.c
|
||||
*/
|
||||
void GeoCoord::latLongToOLC(double lat, double lon, OLC &olc) {
|
||||
char tempCode[] = "1234567890abc";
|
||||
const char kAlphabet[] = "23456789CFGHJMPQRVWX";
|
||||
double latitude;
|
||||
double longitude = lon;
|
||||
double latitude_degrees = std::min(90.0, std::max(-90.0, lat));
|
||||
|
||||
if (latitude_degrees < 90) // Check latitude less than lat max
|
||||
latitude = latitude_degrees;
|
||||
else {
|
||||
double precision;
|
||||
if (OLC_CODE_LEN <= 10)
|
||||
precision = pow_neg(20, floor((OLC_CODE_LEN / -2) + 2));
|
||||
else
|
||||
precision = pow_neg(20, -3) / pow(5, OLC_CODE_LEN - 10);
|
||||
latitude = latitude_degrees - precision / 2;
|
||||
}
|
||||
while (longitude < -180) // Normalize longitude
|
||||
longitude += 360;
|
||||
while (longitude >= 180)
|
||||
longitude -= 360;
|
||||
int64_t lat_val = 90 * 2.5e7;
|
||||
int64_t lng_val = 180 * 8.192e6;
|
||||
lat_val += latitude * 2.5e7;
|
||||
lng_val += longitude * 8.192e6;
|
||||
size_t pos = OLC_CODE_LEN;
|
||||
|
||||
if (OLC_CODE_LEN > 10) { // Compute grid part of code if needed
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
int lat_digit = lat_val % 5;
|
||||
int lng_digit = lng_val % 4;
|
||||
int ndx = lat_digit * 4 + lng_digit;
|
||||
tempCode[pos--] = kAlphabet[ndx];
|
||||
lat_val /= 5;
|
||||
lng_val /= 4;
|
||||
}
|
||||
} else {
|
||||
lat_val /= pow(5, 5);
|
||||
lng_val /= pow(4, 5);
|
||||
}
|
||||
|
||||
pos = 10;
|
||||
|
||||
for (size_t i = 0; i < 5; i++) { // Compute pair section of code
|
||||
int lat_ndx = lat_val % 20;
|
||||
int lng_ndx = lng_val % 20;
|
||||
tempCode[pos--] = kAlphabet[lng_ndx];
|
||||
tempCode[pos--] = kAlphabet[lat_ndx];
|
||||
lat_val /= 20;
|
||||
lng_val /= 20;
|
||||
|
||||
if (i == 0)
|
||||
tempCode[pos--] = '+';
|
||||
}
|
||||
|
||||
if (OLC_CODE_LEN < 9) { // Add padding if needed
|
||||
for (size_t i = OLC_CODE_LEN; i < 9; i++)
|
||||
tempCode[i] = '0';
|
||||
tempCode[9] = '+';
|
||||
}
|
||||
|
||||
size_t char_count = OLC_CODE_LEN;
|
||||
if (10 > char_count) {
|
||||
char_count = 10;
|
||||
}
|
||||
for (size_t i = 0; i < char_count; i++) {
|
||||
olc.code[i] = tempCode[i];
|
||||
}
|
||||
olc.code[char_count] = '\0';
|
||||
}
|
||||
|
||||
// Converts the coordinate in WGS84 datum to the OSGB36 datum.
|
||||
void GeoCoord::convertWGS84ToOSGB36(const double lat, const double lon, double &osgb_Latitude, double &osgb_Longitude) {
|
||||
// Convert lat long to cartesian
|
||||
double phi = toRadians(lat);
|
||||
double lambda = toRadians(lon);
|
||||
double h = 0.0; // No OSTN height data used, some loss of accuracy (up to 5m)
|
||||
double wgsA = 6378137; // WGS84 datum semi major axis
|
||||
double wgsF = 1 / 298.257223563; // WGS84 datum flattening
|
||||
double ecc = 2*wgsF - wgsF*wgsF;
|
||||
double vee = wgsA / sqrt(1 - ecc * pow(sin(phi), 2));
|
||||
double wgsX = (vee + h) * cos(phi) * cos(lambda);
|
||||
double wgsY = (vee + h) * cos(phi) * sin(lambda);
|
||||
double wgsZ = ((1 - ecc) * vee + h) * sin(phi);
|
||||
|
||||
// 7-parameter Helmert transform
|
||||
double tx = -446.448; // x shift in meters
|
||||
double ty = 125.157; // y shift in meters
|
||||
double tz = -542.060; // z shift in meters
|
||||
double s = 20.4894/1e6 + 1; // scale normalized parts per million to (s + 1)
|
||||
double rx = toRadians(-0.1502/3600); // x rotation normalize arcseconds to radians
|
||||
double ry = toRadians(-0.2470/3600); // y rotation normalize arcseconds to radians
|
||||
double rz = toRadians(-0.8421/3600); // z rotation normalize arcseconds to radians
|
||||
double osgbX = tx + wgsX*s - wgsY*rz + wgsZ*ry;
|
||||
double osgbY = ty + wgsX*rz + wgsY*s - wgsZ*rx;
|
||||
double osgbZ = tz - wgsX*ry + wgsY*rx + wgsZ*s;
|
||||
|
||||
// Convert cartesian to lat long
|
||||
double airyA = 6377563.396; // Airy1830 datum semi major axis
|
||||
double airyB = 6356256.909; // Airy1830 datum semi minor axis
|
||||
double airyF = 1/ 299.3249646; // Airy1830 datum flattening
|
||||
double airyEcc = 2*airyF - airyF*airyF;
|
||||
double airyEcc2 = airyEcc / (1 - airyEcc);
|
||||
double p = sqrt(osgbX*osgbX + osgbY*osgbY);
|
||||
double R = sqrt(p*p + osgbZ*osgbZ);
|
||||
double tanBeta = (airyB*osgbZ) / (airyA*p) * (1 + airyEcc2*airyB/R);
|
||||
double sinBeta = tanBeta / sqrt(1 + tanBeta*tanBeta);
|
||||
double cosBeta = sinBeta / tanBeta;
|
||||
osgb_Latitude = atan2(osgbZ + airyEcc2*airyB*sinBeta*sinBeta*sinBeta, p - airyEcc*airyA*cosBeta*cosBeta*cosBeta); // leave in radians
|
||||
osgb_Longitude = atan2(osgbY, osgbX); // leave in radians
|
||||
//osgb height = p*cos(osgb.latitude) + osgbZ*sin(osgb.latitude) -
|
||||
//(airyA*airyA/(airyA / sqrt(1 - airyEcc*sin(osgb.latitude)*sin(osgb.latitude)))); // Not used, no OSTN data
|
||||
}
|
||||
|
||||
/// Ported from my old java code, returns distance in meters along the globe
|
||||
/// surface (by magic?)
|
||||
float GeoCoord::latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
||||
{
|
||||
double pk = (180 / 3.14169);
|
||||
double a1 = lat_a / pk;
|
||||
double a2 = lng_a / pk;
|
||||
double b1 = lat_b / pk;
|
||||
double b2 = lng_b / pk;
|
||||
double cos_b1 = cos(b1);
|
||||
double cos_a1 = cos(a1);
|
||||
double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2);
|
||||
double t2 = cos_a1 * sin(a2) * cos_b1 * sin(b2);
|
||||
double t3 = sin(a1) * sin(b1);
|
||||
double tt = acos(t1 + t2 + t3);
|
||||
if (std::isnan(tt))
|
||||
tt = 0.0; // Must have been the same point?
|
||||
|
||||
return (float)(6366000 * tt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bearing in degrees between two points on Earth. Ported from my
|
||||
* old Gaggle android app.
|
||||
*
|
||||
* @param lat1
|
||||
* Latitude of the first point
|
||||
* @param lon1
|
||||
* Longitude of the first point
|
||||
* @param lat2
|
||||
* Latitude of the second point
|
||||
* @param lon2
|
||||
* Longitude of the second point
|
||||
* @return Bearing between the two points in radians. A value of 0 means due
|
||||
* north.
|
||||
*/
|
||||
float GeoCoord::bearing(double lat1, double lon1, double lat2, double lon2)
|
||||
{
|
||||
double lat1Rad = toRadians(lat1);
|
||||
double lat2Rad = toRadians(lat2);
|
||||
double deltaLonRad = toRadians(lon2 - lon1);
|
||||
double y = sin(deltaLonRad) * cos(lat2Rad);
|
||||
double x = cos(lat1Rad) * sin(lat2Rad) - (sin(lat1Rad) * cos(lat2Rad) * cos(deltaLonRad));
|
||||
return atan2(y, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ported from http://www.edwilliams.org/avform147.htm#Intro
|
||||
* @brief Convert from meters to range in radians on a great circle
|
||||
* @param range_meters
|
||||
* The range in meters
|
||||
* @return range in radians on a great circle
|
||||
*/
|
||||
float GeoCoord::rangeMetersToRadians(double range_meters) {
|
||||
// 1 nm is 1852 meters
|
||||
double distance_nm = range_meters * 1852;
|
||||
return (PI / (180 * 60)) *distance_nm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ported from http://www.edwilliams.org/avform147.htm#Intro
|
||||
* @brief Convert from radians to range in meters on a great circle
|
||||
* @param range_radians
|
||||
* The range in radians
|
||||
* @return Range in meters on a great circle
|
||||
*/
|
||||
float GeoCoord::rangeRadiansToMeters(double range_radians) {
|
||||
double distance_nm = ((180 * 60) / PI) * range_radians;
|
||||
// 1 meter is 0.000539957 nm
|
||||
return distance_nm * 0.000539957;
|
||||
}
|
||||
|
||||
// Find distance from point to passed in point
|
||||
int32_t GeoCoord::distanceTo(GeoCoord pointB) {
|
||||
return latLongToMeter(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
|
||||
}
|
||||
|
||||
// Find bearing from point to passed in point
|
||||
int32_t GeoCoord::bearingTo(GeoCoord pointB) {
|
||||
return bearing(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new point bassed on the passed in poin
|
||||
* Ported from http://www.edwilliams.org/avform147.htm#LL
|
||||
* @param bearing
|
||||
* The bearing in raidans
|
||||
* @param range_meters
|
||||
* range in meters
|
||||
* @return GeoCoord object of point at bearing and range from initial point
|
||||
*/
|
||||
std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range_meters) {
|
||||
double range_radians = rangeMetersToRadians(range_meters);
|
||||
double lat1 = this->getLatitude() * 1e-7;
|
||||
double lon1 = this->getLongitude() * 1e-7;
|
||||
double lat = asin(sin(lat1) * cos(range_radians) + cos(lat1) * sin(range_radians) * cos(bearing));
|
||||
double dlon = atan2(sin(bearing) * sin(range_radians) * cos(lat1), cos(range_radians) - sin(lat1) * sin(lat));
|
||||
double lon = fmod(lon1 - dlon + PI, 2 * PI) - PI;
|
||||
|
||||
return std::make_shared<GeoCoord>(double(lat), double(lon), this->getAltitude());
|
||||
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define OLC_CODE_LEN 11
|
||||
|
||||
// Helper functions
|
||||
// Raises a number to an exponent, handling negative exponents.
|
||||
static inline double pow_neg(double base, double exponent) {
|
||||
if (exponent == 0) {
|
||||
return 1;
|
||||
} else if (exponent > 0) {
|
||||
return pow(base, exponent);
|
||||
}
|
||||
return 1 / pow(base, -exponent);
|
||||
}
|
||||
|
||||
static inline double toRadians(double deg)
|
||||
{
|
||||
return deg * PI / 180;
|
||||
}
|
||||
|
||||
static inline double toDegrees(double r)
|
||||
{
|
||||
return r * 180 / PI;
|
||||
}
|
||||
|
||||
// GeoCoord structs/classes
|
||||
// A struct to hold the data for a DMS coordinate.
|
||||
struct DMS
|
||||
{
|
||||
uint8_t latDeg;
|
||||
uint8_t latMin;
|
||||
uint32_t latSec;
|
||||
char latCP;
|
||||
uint8_t lonDeg;
|
||||
uint8_t lonMin;
|
||||
uint32_t lonSec;
|
||||
char lonCP;
|
||||
};
|
||||
|
||||
// A struct to hold the data for a UTM coordinate, this is also used when creating an MGRS coordinate.
|
||||
struct UTM
|
||||
{
|
||||
uint8_t zone;
|
||||
char band;
|
||||
uint32_t easting;
|
||||
uint32_t northing;
|
||||
};
|
||||
|
||||
// A struct to hold the data for a MGRS coordinate.
|
||||
struct MGRS
|
||||
{
|
||||
uint8_t zone;
|
||||
char band;
|
||||
char east100k;
|
||||
char north100k;
|
||||
uint32_t easting;
|
||||
uint32_t northing;
|
||||
};
|
||||
|
||||
// A struct to hold the data for a OSGR coordiante
|
||||
struct OSGR {
|
||||
char e100k;
|
||||
char n100k;
|
||||
uint32_t easting;
|
||||
uint32_t northing;
|
||||
};
|
||||
|
||||
// A struct to hold the data for a OLC coordinate
|
||||
struct OLC {
|
||||
char code[OLC_CODE_LEN + 1]; // +1 for null termination
|
||||
};
|
||||
|
||||
class GeoCoord {
|
||||
private:
|
||||
int32_t _latitude = 0;
|
||||
int32_t _longitude = 0;
|
||||
int32_t _altitude = 0;
|
||||
|
||||
DMS _dms;
|
||||
UTM _utm;
|
||||
MGRS _mgrs;
|
||||
OSGR _osgr;
|
||||
OLC _olc;
|
||||
|
||||
bool _dirty = true;
|
||||
|
||||
void setCoords();
|
||||
|
||||
public:
|
||||
GeoCoord();
|
||||
GeoCoord(int32_t lat, int32_t lon, int32_t alt);
|
||||
GeoCoord(double lat, double lon, int32_t alt);
|
||||
GeoCoord(float lat, float lon, int32_t alt);
|
||||
|
||||
void updateCoords(const int32_t lat, const int32_t lon, const int32_t alt);
|
||||
void updateCoords(const double lat, const double lon, const int32_t alt);
|
||||
void updateCoords(const float lat, const float lon, const int32_t alt);
|
||||
|
||||
// Conversions
|
||||
static void latLongToDMS(const double lat, const double lon, DMS &dms);
|
||||
static void latLongToUTM(const double lat, const double lon, UTM &utm);
|
||||
static void latLongToMGRS(const double lat, const double lon, MGRS &mgrs);
|
||||
static void latLongToOSGR(const double lat, const double lon, OSGR &osgr);
|
||||
static void latLongToOLC(const double lat, const double lon, OLC &olc);
|
||||
static void convertWGS84ToOSGB36(const double lat, const double lon, double &osgb_Latitude, double &osgb_Longitude);
|
||||
static float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b);
|
||||
static float bearing(double lat1, double lon1, double lat2, double lon2);
|
||||
static float rangeRadiansToMeters(double range_radians);
|
||||
static float rangeMetersToRadians(double range_meters);
|
||||
|
||||
// Point to point conversions
|
||||
int32_t distanceTo(GeoCoord pointB);
|
||||
int32_t bearingTo(GeoCoord pointB);
|
||||
std::shared_ptr<GeoCoord> pointAtDistance(double bearing, double range);
|
||||
|
||||
// Lat lon alt getters
|
||||
int32_t getLatitude() const { return _latitude; }
|
||||
int32_t getLongitude() const { return _longitude; }
|
||||
int32_t getAltitude() const { return _altitude; }
|
||||
|
||||
// DMS getters
|
||||
uint8_t getDMSLatDeg() const { return _dms.latDeg; }
|
||||
uint8_t getDMSLatMin() const { return _dms.latMin; }
|
||||
uint32_t getDMSLatSec() const { return _dms.latSec; }
|
||||
char getDMSLatCP() const { return _dms.latCP; }
|
||||
uint8_t getDMSLonDeg() const { return _dms.lonDeg; }
|
||||
uint8_t getDMSLonMin() const { return _dms.lonMin; }
|
||||
uint32_t getDMSLonSec() const { return _dms.lonSec; }
|
||||
char getDMSLonCP() const { return _dms.lonCP; }
|
||||
|
||||
// UTM getters
|
||||
uint8_t getUTMZone() const { return _utm.zone; }
|
||||
char getUTMBand() const { return _utm.band; }
|
||||
uint32_t getUTMEasting() const { return _utm.easting; }
|
||||
uint32_t getUTMNorthing() const { return _utm.northing; }
|
||||
|
||||
// MGRS getters
|
||||
uint8_t getMGRSZone() const { return _mgrs.zone; }
|
||||
char getMGRSBand() const { return _mgrs.band; }
|
||||
char getMGRSEast100k() const { return _mgrs.east100k; }
|
||||
char getMGRSNorth100k() const { return _mgrs.north100k; }
|
||||
uint32_t getMGRSEasting() const { return _mgrs.easting; }
|
||||
uint32_t getMGRSNorthing() const { return _mgrs.northing; }
|
||||
|
||||
// OSGR getters
|
||||
char getOSGRE100k() const { return _osgr.e100k; }
|
||||
char getOSGRN100k() const { return _osgr.n100k; }
|
||||
uint32_t getOSGREasting() const { return _osgr.easting; }
|
||||
uint32_t getOSGRNorthing() const { return _osgr.northing; }
|
||||
|
||||
// OLC getter
|
||||
void getOLCCode(char* code) { strncpy(code, _olc.code, OLC_CODE_LEN + 1); } // +1 for null termination
|
||||
};
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
#include "NMEAGPS.h"
|
||||
#include "RTC.h"
|
||||
|
||||
#include <TinyGPS++.h>
|
||||
|
||||
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
|
||||
#define GPS_SOL_EXPIRY_MS 300 // in millis
|
||||
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
|
||||
|
||||
static int32_t toDegInt(RawDegrees d)
|
||||
{
|
||||
int32_t degMult = 10000000; // 1e7
|
||||
@@ -27,17 +21,6 @@ bool NMEAGPS::setupGPS()
|
||||
pinMode(PIN_GPS_PPS, INPUT);
|
||||
#endif
|
||||
|
||||
// Currently disabled per issue #525 (TinyGPS++ crash bug)
|
||||
// when fixed upstream, can be un-disabled to enable 3D FixType and PDOP
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// see NMEAGPS.h
|
||||
gsafixtype.begin(reader, NMEA_MSG_GXGSA, 2);
|
||||
gsapdop.begin(reader, NMEA_MSG_GXGSA, 15);
|
||||
DEBUG_MSG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
|
||||
#else
|
||||
DEBUG_MSG("GxGSA NOT available\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -65,7 +48,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
t.tm_year = d.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
DEBUG_MSG("NMEA GPS time %d\n", t.tm_sec);
|
||||
|
||||
|
||||
perhapsSetRTC(RTCQualityGPS, t);
|
||||
|
||||
return true;
|
||||
@@ -81,140 +64,47 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
*/
|
||||
bool NMEAGPS::lookForLocation()
|
||||
{
|
||||
// By default, TinyGPS++ does not parse GPGSA lines, which give us
|
||||
// the 2D/3D fixType (see NMEAGPS.h)
|
||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||
fixQual = reader.fixQuality();
|
||||
bool foundLocation = false;
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
fixType = atoi(gsafixtype.value()); // will set to zero if no data
|
||||
DEBUG_MSG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||
#endif
|
||||
// uint8_t fixtype = reader.fixQuality();
|
||||
// hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
|
||||
|
||||
// check if GPS has an acceptable lock
|
||||
if (! hasLock())
|
||||
return false;
|
||||
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n",
|
||||
reader.location.age(),
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
gsafixtype.age(),
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
reader.date.age(), reader.time.age());
|
||||
#endif // GPS_EXTRAVERBOSE
|
||||
|
||||
// check if a complete GPS solution set is available for reading
|
||||
// tinyGPSDatum::age() also includes isValid() test
|
||||
// FIXME
|
||||
if (! ((reader.location.age() < GPS_SOL_EXPIRY_MS) &&
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
(gsafixtype.age() < GPS_SOL_EXPIRY_MS) &&
|
||||
#endif
|
||||
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
|
||||
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
|
||||
{
|
||||
DEBUG_MSG("SOME data is TOO OLD\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this a new point or are we re-reading the previous one?
|
||||
if (! reader.location.isUpdated())
|
||||
return false;
|
||||
|
||||
// We know the solution is fresh and valid, so just read the data
|
||||
auto loc = reader.location.value();
|
||||
|
||||
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
|
||||
// Bail out EARLY to avoid overwriting previous good data (like #857)
|
||||
if(toDegInt(loc.lat) == 0) {
|
||||
DEBUG_MSG("Ignoring bogus NMEA position\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
|
||||
|
||||
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
p.HDOP = reader.hdop.value();
|
||||
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
|
||||
DEBUG_MSG("PDOP=%d, HDOP=%d\n", dop, reader.hdop.value());
|
||||
#else
|
||||
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
|
||||
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
|
||||
p.HDOP = reader.hdop.value();
|
||||
p.PDOP = 1.41 * reader.hdop.value();
|
||||
#endif
|
||||
|
||||
// Discard incomplete or erroneous readings
|
||||
if (reader.hdop.value() == 0)
|
||||
return false;
|
||||
|
||||
p.latitude_i = toDegInt(loc.lat);
|
||||
p.longitude_i = toDegInt(loc.lng);
|
||||
|
||||
p.alt_geoid_sep = reader.geoidHeight.meters();
|
||||
p.altitude_hae = reader.altitude.meters() + p.alt_geoid_sep;
|
||||
p.altitude = reader.altitude.meters();
|
||||
|
||||
p.fix_quality = fixQual;
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
p.fix_type = fixType;
|
||||
#endif
|
||||
|
||||
// positional timestamp
|
||||
struct tm t;
|
||||
t.tm_sec = reader.time.second();
|
||||
t.tm_min = reader.time.minute();
|
||||
t.tm_hour = reader.time.hour();
|
||||
t.tm_mday = reader.date.day();
|
||||
t.tm_mon = reader.date.month() - 1;
|
||||
t.tm_year = reader.date.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
p.pos_timestamp = mktime(&t);
|
||||
|
||||
// Nice to have, if available
|
||||
if (reader.satellites.isUpdated()) {
|
||||
p.sats_in_view = reader.satellites.value();
|
||||
setNumSatellites(reader.satellites.value());
|
||||
}
|
||||
|
||||
if (reader.course.isUpdated() && reader.course.isValid()) {
|
||||
if (reader.course.value() < 36000) { // sanity check
|
||||
p.ground_track = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
|
||||
} else {
|
||||
DEBUG_MSG("BOGUS course.value() REJECTED: %d\n",
|
||||
reader.course.value());
|
||||
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
||||
if (reader.hdop.isUpdated()) {
|
||||
dop = reader.hdop.value();
|
||||
}
|
||||
if (reader.course.isUpdated()) {
|
||||
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
|
||||
}
|
||||
|
||||
if (reader.altitude.isUpdated())
|
||||
altitude = reader.altitude.meters();
|
||||
|
||||
if (reader.location.isUpdated()) {
|
||||
|
||||
auto loc = reader.location.value();
|
||||
latitude = toDegInt(loc.lat);
|
||||
longitude = toDegInt(loc.lng);
|
||||
|
||||
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
|
||||
if(longitude == 0)
|
||||
DEBUG_MSG("Ignoring bogus NMEA position\n");
|
||||
else {
|
||||
foundLocation = true;
|
||||
|
||||
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
||||
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,
|
||||
dop * 1e-2, heading * 1e-5);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// REDUNDANT?
|
||||
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
||||
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, dop=%g, heading=%f\n",
|
||||
latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2,
|
||||
heading * 1e-5);
|
||||
*/
|
||||
return true;
|
||||
return foundLocation;
|
||||
}
|
||||
|
||||
|
||||
bool NMEAGPS::hasLock()
|
||||
{
|
||||
// Using GPGGA fix quality indicator
|
||||
if (fixQual >= 1 && fixQual <= 5) {
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// Use GPGSA fix type 2D/3D (better) if available
|
||||
if (fixType == 3 || fixType == 0) // zero means "no data received"
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool NMEAGPS::whileIdle()
|
||||
{
|
||||
bool isValid = false;
|
||||
|
||||
@@ -12,15 +12,6 @@
|
||||
class NMEAGPS : public GPS
|
||||
{
|
||||
TinyGPSPlus reader;
|
||||
uint8_t fixQual = 0; // fix quality from GPGGA
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
|
||||
// via optional feature "custom fields", currently disabled (bug #525)
|
||||
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
|
||||
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
|
||||
uint8_t fixType = 0; // fix type from GPGSA
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual bool setupGPS();
|
||||
@@ -47,6 +38,4 @@ class NMEAGPS : public GPS
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation();
|
||||
|
||||
virtual bool hasLock();
|
||||
};
|
||||
|
||||
@@ -5,15 +5,6 @@
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
|
||||
// if gps_update_interval below this value, do not powercycle the GPS
|
||||
#define UBLOX_POWEROFF_THRESHOLD 90
|
||||
|
||||
#define PDOP_INVALID 9999
|
||||
|
||||
// #define UBX_MODE_NMEA
|
||||
|
||||
extern RadioConfig radioConfig;
|
||||
|
||||
UBloxGPS::UBloxGPS() {}
|
||||
|
||||
bool UBloxGPS::tryConnect()
|
||||
@@ -50,22 +41,12 @@ bool UBloxGPS::setupGPS()
|
||||
delay(500);
|
||||
|
||||
if (isConnected()) {
|
||||
#ifdef UBX_MODE_NMEA
|
||||
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
|
||||
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
|
||||
#else
|
||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||
#endif
|
||||
|
||||
if (!setUBXMode())
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||
|
||||
#ifdef UBX_MODE_NMEA
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -73,17 +54,6 @@ bool UBloxGPS::setupGPS()
|
||||
|
||||
bool UBloxGPS::setUBXMode()
|
||||
{
|
||||
#ifdef UBX_MODE_NMEA
|
||||
if (_serial_gps) {
|
||||
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
|
||||
}
|
||||
if (i2cAddress) {
|
||||
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
|
||||
}
|
||||
|
||||
return false; // pretend initialization failed to force NMEA mode
|
||||
#endif
|
||||
|
||||
if (_serial_gps) {
|
||||
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
|
||||
return false;
|
||||
@@ -141,17 +111,19 @@ bool UBloxGPS::factoryReset()
|
||||
/** Idle processing while GPS is looking for lock */
|
||||
void UBloxGPS::whileActive()
|
||||
{
|
||||
ublox.flushPVT(); // reset ALL freshness flags first
|
||||
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
|
||||
|
||||
// Ask for a new position fix - hopefully it will have results ready by next time
|
||||
// the order here is important, because we only check for has latitude when reading
|
||||
ublox.getSIV(maxWait());
|
||||
ublox.getPDOP(maxWait());
|
||||
ublox.getP(maxWait());
|
||||
|
||||
//ublox.getSIV(maxWait()); // redundant with getPDOP below
|
||||
ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others
|
||||
ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others
|
||||
|
||||
// the fixType flag will be checked and updated in lookForLocation()
|
||||
// Update fixtype
|
||||
if (ublox.moduleQueried.fixType) {
|
||||
fixType = ublox.getFixType(0);
|
||||
// DEBUG_MSG("GPS fix type %d, numSats %d\n", fixType, numSatellites);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,110 +164,33 @@ bool UBloxGPS::lookForLocation()
|
||||
{
|
||||
bool foundLocation = false;
|
||||
|
||||
// check if a complete GPS solution set is available for reading
|
||||
// (some of these, like lat/lon are redundant and can be removed)
|
||||
if ( ! (ublox.moduleQueried.fixType &&
|
||||
ublox.moduleQueried.latitude &&
|
||||
ublox.moduleQueried.longitude &&
|
||||
ublox.moduleQueried.altitude &&
|
||||
ublox.moduleQueried.pDOP &&
|
||||
ublox.moduleQueried.SIV &&
|
||||
ublox.moduleQueried.gpsDay))
|
||||
{
|
||||
// Not ready? No problem! We'll try again later.
|
||||
return false;
|
||||
}
|
||||
if (ublox.moduleQueried.SIV)
|
||||
setNumSatellites(ublox.getSIV(0));
|
||||
|
||||
fixType = ublox.getFixType();
|
||||
#ifdef UBLOX_EXTRAVERBOSE
|
||||
DEBUG_MSG("FixType=%d\n", fixType);
|
||||
#endif
|
||||
if (ublox.moduleQueried.pDOP)
|
||||
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
||||
|
||||
// we only notify if position has changed due to a new fix
|
||||
if ((fixType >= 3 && fixType <= 4)) {
|
||||
if (ublox.moduleQueried.latitude) // rd fixes only
|
||||
{
|
||||
latitude = ublox.getLatitude(0);
|
||||
longitude = ublox.getLongitude(0);
|
||||
altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters
|
||||
|
||||
// check if GPS has an acceptable lock
|
||||
if (! hasLock()) {
|
||||
ublox.flushPVT(); // reset ALL freshness flags
|
||||
return false;
|
||||
}
|
||||
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
|
||||
// don't read it here - it will generate an ignored getPVT command on the 6ms
|
||||
// heading = ublox.getHeading(0);
|
||||
|
||||
// read lat/lon/alt/dop data into temporary variables to avoid
|
||||
// overwriting global variables with potentially invalid data
|
||||
int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
||||
int32_t tmp_lat = ublox.getLatitude(0);
|
||||
int32_t tmp_lon = ublox.getLongitude(0);
|
||||
int32_t tmp_alt_msl = ublox.getAltitudeMSL(0);
|
||||
int32_t tmp_alt_hae = ublox.getAltitude(0);
|
||||
int32_t max_dop = PDOP_INVALID;
|
||||
if (radioConfig.preferences.gps_max_dop)
|
||||
max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling
|
||||
|
||||
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
|
||||
// don't read it here - it will generate an ignored getPVT command on the 6ms
|
||||
// heading = ublox.getHeading(0);
|
||||
|
||||
// read positional timestamp
|
||||
struct tm t;
|
||||
t.tm_sec = ublox.getSecond(0);
|
||||
t.tm_min = ublox.getMinute(0);
|
||||
t.tm_hour = ublox.getHour(0);
|
||||
t.tm_mday = ublox.getDay(0);
|
||||
t.tm_mon = ublox.getMonth(0) - 1;
|
||||
t.tm_year = ublox.getYear(0) - 1900;
|
||||
t.tm_isdst = false;
|
||||
|
||||
time_t tmp_ts = mktime(&t);
|
||||
|
||||
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
|
||||
|
||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||
// FIXME - NULL ISLAND is a real location on Earth!
|
||||
foundLocation = (tmp_lat != 0) && (tmp_lon != 0) &&
|
||||
(tmp_lat <= 900000000) && (tmp_lat >= -900000000) &&
|
||||
(tmp_dop < max_dop);
|
||||
|
||||
// only if entire dataset is valid, update globals from temp vars
|
||||
if (foundLocation) {
|
||||
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
|
||||
p.longitude_i = tmp_lon;
|
||||
p.latitude_i = tmp_lat;
|
||||
if (fixType > 2) {
|
||||
// if fix is 2d, ignore altitude data
|
||||
p.altitude = tmp_alt_msl / 1000;
|
||||
p.altitude_hae = tmp_alt_hae / 1000;
|
||||
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
|
||||
} else {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("no altitude data (fixType=%d)\n", fixType);
|
||||
#endif
|
||||
// clean up old values in case it's a 3d-2d fix transition
|
||||
p.altitude = p.altitude_hae = p.alt_geoid_sep = 0;
|
||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||
foundLocation = (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000);
|
||||
}
|
||||
p.pos_timestamp = tmp_ts;
|
||||
p.PDOP = tmp_dop;
|
||||
p.fix_type = fixType;
|
||||
p.sats_in_view = ublox.getSIV(0);
|
||||
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
|
||||
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
|
||||
} else {
|
||||
// INVALID solution - should never happen
|
||||
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
|
||||
tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop);
|
||||
}
|
||||
|
||||
ublox.flushPVT(); // reset ALL freshness flags at the end
|
||||
|
||||
return foundLocation;
|
||||
}
|
||||
|
||||
bool UBloxGPS::hasLock()
|
||||
{
|
||||
if (radioConfig.preferences.gps_accept_2d)
|
||||
return (fixType >= 2 && fixType <= 4);
|
||||
else
|
||||
return (fixType >= 3 && fixType <= 4);
|
||||
}
|
||||
|
||||
bool UBloxGPS::whileIdle()
|
||||
{
|
||||
// if using i2c or serial look too see if any chars are ready
|
||||
@@ -306,20 +201,15 @@ bool UBloxGPS::whileIdle()
|
||||
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
|
||||
void UBloxGPS::sleep()
|
||||
{
|
||||
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
|
||||
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
|
||||
ublox.powerOff();
|
||||
// setGPSPower(false);
|
||||
}
|
||||
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
|
||||
ublox.powerOff();
|
||||
// setGPSPower(false);
|
||||
}
|
||||
|
||||
void UBloxGPS::wake()
|
||||
{
|
||||
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
|
||||
fixType = 0; // assume we have no fix yet
|
||||
}
|
||||
fixType = 0; // assume we hace no fix yet
|
||||
|
||||
// this is idempotent
|
||||
setGPSPower(true);
|
||||
|
||||
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
|
||||
|
||||
@@ -54,7 +54,6 @@ class UBloxGPS : public GPS
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation();
|
||||
virtual bool hasLock();
|
||||
|
||||
/// If possible force the GPS into sleep/low power mode
|
||||
virtual void sleep();
|
||||
|
||||
@@ -35,7 +35,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
@@ -73,9 +72,6 @@ std::vector<MeshPlugin *> pluginFrames;
|
||||
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||
static char ourId[5];
|
||||
|
||||
// GeoCoord object for the screen
|
||||
GeoCoord geoCoord;
|
||||
|
||||
#ifdef SHOW_REDRAWS
|
||||
static bool heartbeat = false;
|
||||
#endif
|
||||
@@ -147,17 +143,6 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
drawIconScreen(region, display, state, x, y);
|
||||
}
|
||||
|
||||
// Used on boot when a certificate is being created
|
||||
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, y, "Creating SSL certificate");
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait...");
|
||||
}
|
||||
|
||||
#ifdef HAS_EINK
|
||||
/// Used on eink displays while in deep sleep
|
||||
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@@ -237,13 +222,6 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
|
||||
}
|
||||
|
||||
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward plugin are enabled
|
||||
static bool shouldDrawMessage(const MeshPacket *packet) {
|
||||
return packet->from != 0 &&
|
||||
!radioConfig.preferences.range_test_plugin_enabled &&
|
||||
!radioConfig.preferences.store_forward_plugin_enabled;
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -355,11 +333,6 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
|
||||
// Draw GPS status summary
|
||||
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
if (radioConfig.preferences.fixed_position) {
|
||||
// GPS coordinates are currently fixed
|
||||
display->drawString(x - 1, y - 2, "Fixed GPS");
|
||||
return;
|
||||
}
|
||||
if (!gps->getIsConnected()) {
|
||||
display->drawString(x, y - 2, "No GPS");
|
||||
return;
|
||||
@@ -394,15 +367,15 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
|
||||
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
String displayLine = "";
|
||||
if (!gps->getIsConnected() && !radioConfig.preferences.fixed_position) {
|
||||
if (!gps->getIsConnected()) {
|
||||
// displayLine = "No GPS Module";
|
||||
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else if (!gps->getHasLock() && !radioConfig.preferences.fixed_position) {
|
||||
} else if (!gps->getHasLock()) {
|
||||
// displayLine = "No GPS Lock";
|
||||
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else {
|
||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||
displayLine = "Altitude: " + String(geoCoord.getAltitude()) + "m";
|
||||
|
||||
displayLine = "Altitude: " + String(gps->getAltitude()) + "m";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
}
|
||||
}
|
||||
@@ -410,51 +383,76 @@ static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GP
|
||||
// Draw GPS status coordinates
|
||||
static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
auto gpsFormat = radioConfig.preferences.gps_format;
|
||||
String displayLine = "";
|
||||
|
||||
if (!gps->getIsConnected() && !radioConfig.preferences.fixed_position) {
|
||||
if (!gps->getIsConnected()) {
|
||||
displayLine = "No GPS Module";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else if (!gps->getHasLock() && !radioConfig.preferences.fixed_position) {
|
||||
} else if (!gps->getHasLock()) {
|
||||
displayLine = "No GPS Lock";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else {
|
||||
if (gpsFormat != GpsCoordinateFormat_GpsFormatDMS) {
|
||||
char coordinateLine[22];
|
||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||
if (gpsFormat == GpsCoordinateFormat_GpsFormatDec) { // Decimal Degrees
|
||||
sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7);
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatUTM) { // Universal Transverse Mercator
|
||||
sprintf(coordinateLine, "%2i%1c %06i %07i", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
|
||||
geoCoord.getUTMEasting(), geoCoord.getUTMNorthing());
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatMGRS) { // Military Grid Reference System
|
||||
sprintf(coordinateLine, "%2i%1c %1c%1c %05i %05i", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(), geoCoord.getMGRSEast100k(),
|
||||
geoCoord.getMGRSNorth100k(), geoCoord.getMGRSEasting(), geoCoord.getMGRSNorthing());
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOLC) { // Open Location Code
|
||||
geoCoord.getOLCCode(coordinateLine);
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOSGR) { // Ordnance Survey Grid Reference
|
||||
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region
|
||||
sprintf(coordinateLine, "%s", "Out of Boundary");
|
||||
else
|
||||
sprintf(coordinateLine, "%1c%1c %05i %05i", geoCoord.getOSGRE100k(),geoCoord.getOSGRN100k(),
|
||||
geoCoord.getOSGREasting(), geoCoord.getOSGRNorthing());
|
||||
}
|
||||
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
|
||||
} else {
|
||||
char latLine[22];
|
||||
char lonLine[22];
|
||||
sprintf(latLine, "%2i° %2i' %2.4f\" %1c", geoCoord.getDMSLatDeg(), geoCoord.getDMSLatMin(), geoCoord.getDMSLatSec(),
|
||||
geoCoord.getDMSLatCP());
|
||||
sprintf(lonLine, "%3i° %2i' %2.4f\" %1c", geoCoord.getDMSLonDeg(), geoCoord.getDMSLonMin(), geoCoord.getDMSLonSec(),
|
||||
geoCoord.getDMSLonCP());
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(latLine))) / 2, y - FONT_HEIGHT_SMALL * 1, latLine);
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(lonLine))) / 2, y, lonLine);
|
||||
}
|
||||
char coordinateLine[22];
|
||||
sprintf(coordinateLine, "%f %f", gps->getLatitude() * 1e-7, gps->getLongitude() * 1e-7);
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
|
||||
}
|
||||
}
|
||||
|
||||
/// Ported from my old java code, returns distance in meters along the globe
|
||||
/// surface (by magic?)
|
||||
static float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
||||
{
|
||||
double pk = (180 / 3.14169);
|
||||
double a1 = lat_a / pk;
|
||||
double a2 = lng_a / pk;
|
||||
double b1 = lat_b / pk;
|
||||
double b2 = lng_b / pk;
|
||||
double cos_b1 = cos(b1);
|
||||
double cos_a1 = cos(a1);
|
||||
double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2);
|
||||
double t2 = cos_a1 * sin(a2) * cos_b1 * sin(b2);
|
||||
double t3 = sin(a1) * sin(b1);
|
||||
double tt = acos(t1 + t2 + t3);
|
||||
if (isnan(tt))
|
||||
tt = 0.0; // Must have been the same point?
|
||||
|
||||
return (float)(6366000 * tt);
|
||||
}
|
||||
|
||||
static inline double toRadians(double deg)
|
||||
{
|
||||
return deg * PI / 180;
|
||||
}
|
||||
|
||||
static inline double toDegrees(double r)
|
||||
{
|
||||
return r * 180 / PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bearing in degrees between two points on Earth. Ported from my
|
||||
* old Gaggle android app.
|
||||
*
|
||||
* @param lat1
|
||||
* Latitude of the first point
|
||||
* @param lon1
|
||||
* Longitude of the first point
|
||||
* @param lat2
|
||||
* Latitude of the second point
|
||||
* @param lon2
|
||||
* Longitude of the second point
|
||||
* @return Bearing between the two points in radians. A value of 0 means due
|
||||
* north.
|
||||
*/
|
||||
static float bearing(double lat1, double lon1, double lat2, double lon2)
|
||||
{
|
||||
double lat1Rad = toRadians(lat1);
|
||||
double lat2Rad = toRadians(lat2);
|
||||
double deltaLonRad = toRadians(lon2 - lon1);
|
||||
double y = sin(deltaLonRad) * cos(lat2Rad);
|
||||
double x = cos(lat1Rad) * sin(lat2Rad) - (sin(lat1Rad) * cos(lat2Rad) * cos(deltaLonRad));
|
||||
return atan2(y, x);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@@ -515,11 +513,11 @@ static float estimatedHeading(double lat, double lon)
|
||||
return b;
|
||||
}
|
||||
|
||||
float d = GeoCoord::latLongToMeter(oldLat, oldLon, lat, lon);
|
||||
float d = latLongToMeter(oldLat, oldLon, lat, lon);
|
||||
if (d < 10) // haven't moved enough, just keep current bearing
|
||||
return b;
|
||||
|
||||
b = GeoCoord::bearing(oldLat, oldLon, lat, lon);
|
||||
b = bearing(oldLat, oldLon, lat, lon);
|
||||
oldLat = lat;
|
||||
oldLon = lon;
|
||||
|
||||
@@ -639,7 +637,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
// display direction toward node
|
||||
hasNodeHeading = true;
|
||||
Position &p = node->position;
|
||||
float d = GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
float d = latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
@@ -647,7 +645,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
|
||||
// FIXME, also keep the guess at the operators heading and add/substract
|
||||
// it. currently we don't do this and instead draw north up only.
|
||||
float bearingToOther = GeoCoord::bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
float bearingToOther = bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
headingRadian = bearingToOther - myHeading;
|
||||
drawNodeHeading(display, compassX, compassY, headingRadian);
|
||||
}
|
||||
@@ -805,8 +803,6 @@ void Screen::forceDisplay()
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t lastScreenTransition;
|
||||
|
||||
int32_t Screen::runOnce()
|
||||
{
|
||||
// If we don't have a screen, don't ever spend any CPU for us.
|
||||
@@ -883,13 +879,8 @@ int32_t Screen::runOnce()
|
||||
// standard screen switching is stopped.
|
||||
if (showingNormalScreen) {
|
||||
// standard screen loop handling here
|
||||
if (radioConfig.preferences.auto_screen_carousel_secs > 0 &&
|
||||
(millis() - lastScreenTransition) > (radioConfig.preferences.auto_screen_carousel_secs * 1000)) {
|
||||
DEBUG_MSG("LastScreenTransition exceeded %ums transitioning to next frame\n", (millis() - lastScreenTransition));
|
||||
handleOnPress();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate,
|
||||
// ui.getUiState()->frameState); If we are scrolling we need to be called
|
||||
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
|
||||
@@ -916,16 +907,6 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
screen->debugInfo.drawFrameWiFi(display, state, x, y);
|
||||
}
|
||||
|
||||
/* show a message that the SSL cert is being built
|
||||
* it is expected that this will be used during the boot phase */
|
||||
void Screen::setSSLFrames()
|
||||
{
|
||||
DEBUG_MSG("showing SSL frames\n");
|
||||
static FrameCallback sslFrames[] = {drawSSLScreen};
|
||||
ui.setFrames(sslFrames, 1);
|
||||
ui.update();
|
||||
}
|
||||
|
||||
// restore our regular frame list
|
||||
void Screen::setFrames()
|
||||
{
|
||||
@@ -960,10 +941,9 @@ void Screen::setFrames()
|
||||
if (myNodeInfo.error_code)
|
||||
normalFrames[numframes++] = drawCriticalFaultFrame;
|
||||
|
||||
// If we have a text message - show it next, unless it's a phone message and we aren't using any special plugins
|
||||
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
|
||||
// If we have a text message - show it next
|
||||
if (devicestate.has_rx_text_message)
|
||||
normalFrames[numframes++] = drawTextMessageFrame;
|
||||
}
|
||||
|
||||
// then all the nodes
|
||||
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
|
||||
@@ -1053,13 +1033,12 @@ void Screen::handlePrint(const char *text)
|
||||
}
|
||||
|
||||
void Screen::handleOnPress()
|
||||
{
|
||||
{
|
||||
// If screen was off, just wake it, otherwise advance to next frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
DEBUG_MSG("Setting LastScreenTransition\n");
|
||||
lastScreenTransition = millis();
|
||||
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
@@ -1351,8 +1330,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
#endif
|
||||
|
||||
// Line 3
|
||||
if (radioConfig.preferences.gps_format != GpsCoordinateFormat_GpsFormatDMS) // if DMS then don't draw altitude
|
||||
drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||||
drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||||
|
||||
// Line 4
|
||||
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
|
||||
@@ -1394,7 +1372,8 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Screen::handleTextMessage(const MeshPacket *packet) {
|
||||
int Screen::handleTextMessage(const MeshPacket *arg)
|
||||
{
|
||||
if (showingNormalScreen) {
|
||||
setFrames(); // Regen the list of screens (will show new text message)
|
||||
}
|
||||
|
||||
@@ -220,9 +220,6 @@ class Screen : public concurrency::OSThread
|
||||
/// Used to force (super slow) eink displays to draw critical frames
|
||||
void forceDisplay();
|
||||
|
||||
/// Draws our SSL cert screen during boot (called from WebServer)
|
||||
void setSSLFrames();
|
||||
|
||||
protected:
|
||||
/// Updates the UI.
|
||||
//
|
||||
|
||||
40
src/main.cpp
40
src/main.cpp
@@ -39,8 +39,6 @@
|
||||
|
||||
#include "RF95Interface.h"
|
||||
#include "SX1262Interface.h"
|
||||
#include "SX1268Interface.h"
|
||||
#include "LLCC68Interface.h"
|
||||
|
||||
#ifdef NRF52_SERIES
|
||||
#include "variant.h"
|
||||
@@ -493,10 +491,10 @@ void setup()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SX126X_ANT_SW
|
||||
// make analog PA vs not PA switch on SX126x eval board work properly
|
||||
pinMode(SX126X_ANT_SW, OUTPUT);
|
||||
digitalWrite(SX126X_ANT_SW, 1);
|
||||
#ifdef SX1262_ANT_SW
|
||||
// make analog PA vs not PA switch on SX1262 eval board work properly
|
||||
pinMode(SX1262_ANT_SW, OUTPUT);
|
||||
digitalWrite(SX1262_ANT_SW, 1);
|
||||
#endif
|
||||
|
||||
// radio init MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
|
||||
@@ -514,9 +512,9 @@ void setup()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_SX1262)
|
||||
#if defined(SX1262_CS)
|
||||
if (!rIf) {
|
||||
rIf = new SX1262Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
|
||||
rIf = new SX1262Interface(SX1262_CS, SX1262_DIO1, SX1262_RESET, SX1262_BUSY, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find SX1262 radio\n");
|
||||
delete rIf;
|
||||
@@ -527,32 +525,6 @@ void setup()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_SX1268)
|
||||
if (!rIf) {
|
||||
rIf = new SX1268Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find SX1268 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("SX1268 Radio init succeeded, using SX1268 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_LLCC68)
|
||||
if (!rIf) {
|
||||
rIf = new LLCC68Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
|
||||
if (!rIf->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find LLCC68 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("LLCC68 Radio init succeeded, using LLCC68 radio\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SIM_RADIO
|
||||
if (!rIf) {
|
||||
rIf = new SimRadio;
|
||||
|
||||
@@ -17,7 +17,7 @@ ErrorCode FloodingRouter::send(MeshPacket *p)
|
||||
return Router::send(p);
|
||||
}
|
||||
|
||||
bool FloodingRouter::shouldFilterReceived(MeshPacket *p)
|
||||
bool FloodingRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
{
|
||||
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignoring incoming msg, because we've already seen it", p);
|
||||
|
||||
@@ -50,7 +50,7 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p);
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p);
|
||||
|
||||
/**
|
||||
* Look for broadcasts we need to rebroadcast
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#include "SX126xInterface.h"
|
||||
#include "SX126xInterface.cpp"
|
||||
|
||||
// We need this declaration for proper linking in derived classes
|
||||
template class SX126xInterface<SX1262>;
|
||||
template class SX126xInterface<SX1268>;
|
||||
template class SX126xInterface<LLCC68>;
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "configuration.h"
|
||||
#include "LLCC68Interface.h"
|
||||
#include "error.h"
|
||||
|
||||
LLCC68Interface::LLCC68Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
|
||||
SPIClass &spi)
|
||||
: SX126xInterface(cs, irq, rst, busy, spi)
|
||||
{
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "SX126xInterface.h"
|
||||
|
||||
/**
|
||||
* Our adapter for LLCC68 radios
|
||||
* https://www.semtech.com/products/wireless-rf/lora-core/llcc68
|
||||
* ⚠️⚠️⚠️
|
||||
* Be aware that LLCC68 does not support Spreading Factor 12 (SF12) and will not work on the default "Long Slow" channel.
|
||||
* You must change the channel if you get `Critical Error #3` with this module.
|
||||
* ⚠️⚠️⚠️
|
||||
*/
|
||||
class LLCC68Interface : public SX126xInterface<LLCC68>
|
||||
{
|
||||
public:
|
||||
LLCC68Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
|
||||
};
|
||||
@@ -66,7 +66,7 @@ MeshPacket *MeshPlugin::allocErrorResponse(Routing_Error err, const MeshPacket *
|
||||
return r;
|
||||
}
|
||||
|
||||
void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||
{
|
||||
// DEBUG_MSG("In call plugins\n");
|
||||
bool pluginFound = false;
|
||||
@@ -79,7 +79,6 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
|
||||
auto ourNodeNum = nodeDB.getNodeNum();
|
||||
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
|
||||
|
||||
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
|
||||
@@ -88,11 +87,6 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||
|
||||
if ((src == RX_SRC_LOCAL) && !(pi.loopbackOk)) {
|
||||
// new case, monitor separately for now, then FIXME merge above
|
||||
wantsPacket = false;
|
||||
}
|
||||
|
||||
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
|
||||
|
||||
if (wantsPacket) {
|
||||
@@ -122,7 +116,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
printPacket("packet on wrong channel, but can't respond", &mp);
|
||||
} else {
|
||||
|
||||
ProcessMessage handled = pi.handleReceived(mp);
|
||||
bool handled = pi.handleReceived(mp);
|
||||
|
||||
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious
|
||||
// sniffing) also: we only let the one plugin send a reply, once that happens, remaining plugins are not
|
||||
@@ -146,7 +140,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
pi.myReply = NULL;
|
||||
}
|
||||
|
||||
if (handled == ProcessMessage::STOP) {
|
||||
if (handled) {
|
||||
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
|
||||
break;
|
||||
}
|
||||
@@ -175,9 +169,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src)
|
||||
}
|
||||
|
||||
if (!pluginFound)
|
||||
DEBUG_MSG("No plugins interested in portnum=%d, src=%s\n",
|
||||
mp.decoded.portnum,
|
||||
(src == RX_SRC_LOCAL) ? "LOCAL":"REMOTE");
|
||||
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum);
|
||||
}
|
||||
|
||||
MeshPacket *MeshPlugin::allocReply()
|
||||
|
||||
@@ -9,18 +9,6 @@
|
||||
#include <OLEDDisplayUi.h>
|
||||
#endif
|
||||
|
||||
/** handleReceived return enumeration
|
||||
*
|
||||
* Use ProcessMessage::CONTINUE to allows other modules to process a message.
|
||||
*
|
||||
* Use ProcessMessage::STOP to stop further message processing.
|
||||
*/
|
||||
enum class ProcessMessage
|
||||
{
|
||||
CONTINUE = 0,
|
||||
STOP = 1,
|
||||
};
|
||||
|
||||
/** A baseclass for any mesh "plugin".
|
||||
*
|
||||
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||
@@ -45,7 +33,7 @@ class MeshPlugin
|
||||
|
||||
/** For use only by MeshService
|
||||
*/
|
||||
static void callPlugins(const MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
||||
static void callPlugins(const MeshPacket &mp);
|
||||
|
||||
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
|
||||
#ifndef NO_SCREEN
|
||||
@@ -60,10 +48,6 @@ class MeshPlugin
|
||||
*/
|
||||
bool isPromiscuous = false;
|
||||
|
||||
/** Also receive a copy of LOCALLY GENERATED messages - most plugins should leave
|
||||
* this setting disabled - see issue #877 */
|
||||
bool loopbackOk = false;
|
||||
|
||||
/** Most plugins only understand decrypted packets. For plugins that also want to see encrypted packets, they should set this
|
||||
* flag */
|
||||
bool encryptedOk = false;
|
||||
@@ -103,9 +87,9 @@ class MeshPlugin
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) { return ProcessMessage::CONTINUE; }
|
||||
virtual bool handleReceived(const MeshPacket &mp) { return false; }
|
||||
|
||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||
* so that subclasses can (optionally) send a response back to the original sender.
|
||||
|
||||
@@ -112,11 +112,7 @@ bool MeshService::reloadConfig()
|
||||
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
||||
void MeshService::reloadOwner()
|
||||
{
|
||||
// DEBUG_MSG("reloadOwner()\n");
|
||||
// update our local data directly
|
||||
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
|
||||
assert(nodeInfoPlugin);
|
||||
// update everyone else
|
||||
if (nodeInfoPlugin)
|
||||
nodeInfoPlugin->sendOurNodeInfo();
|
||||
nodeDB.saveToDisk();
|
||||
@@ -144,7 +140,7 @@ void MeshService::handleToRadio(MeshPacket &p)
|
||||
|
||||
// Send the packet into the mesh
|
||||
|
||||
sendToMesh(packetPool.allocCopy(p), RX_SRC_USER);
|
||||
sendToMesh(packetPool.allocCopy(p));
|
||||
|
||||
bool loopback = false; // if true send any packet the phone sends back itself (for testing)
|
||||
if (loopback) {
|
||||
@@ -161,12 +157,12 @@ bool MeshService::cancelSending(PacketId id)
|
||||
return router->cancelSending(nodeDB.getNodeNum(), id);
|
||||
}
|
||||
|
||||
void MeshService::sendToMesh(MeshPacket *p, RxSource src)
|
||||
void MeshService::sendToMesh(MeshPacket *p)
|
||||
{
|
||||
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||
|
||||
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
|
||||
router->sendLocal(p, src);
|
||||
router->sendLocal(p);
|
||||
}
|
||||
|
||||
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
@@ -213,39 +209,34 @@ NodeInfo *MeshService::refreshMyNodeInfo()
|
||||
return node;
|
||||
}
|
||||
|
||||
int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
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)
|
||||
NodeInfo *node = refreshMyNodeInfo();
|
||||
Position pos = Position_init_default;
|
||||
Position pos = node->position;
|
||||
|
||||
if (newStatus->getHasLock()) {
|
||||
// load data from GPS object, will add timestamp + battery further down
|
||||
pos = gps->p;
|
||||
if (gps->hasLock()) {
|
||||
if (gps->altitude != 0)
|
||||
pos.altitude = gps->altitude;
|
||||
pos.latitude_i = gps->latitude;
|
||||
pos.longitude_i = gps->longitude;
|
||||
} else {
|
||||
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||
// the old position
|
||||
#if GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("onGPSchanged() - lost validLocation\n");
|
||||
#endif
|
||||
if (radioConfig.preferences.fixed_position) {
|
||||
DEBUG_MSG("WARNING: Using fixed position\n");
|
||||
pos = node->position;
|
||||
} else {
|
||||
// throw away old position
|
||||
pos.latitude_i = 0;
|
||||
pos.longitude_i = 0;
|
||||
pos.altitude = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally add a fresh timestamp and battery level reading
|
||||
// I KNOW this is redundant with refreshMyNodeInfo() above, but these are
|
||||
// inexpensive nonblocking calls and can be refactored in due course
|
||||
pos.time = getValidTime(RTCQualityGPS);
|
||||
pos.battery_level = powerStatus->getBatteryChargePercent();
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB)
|
||||
DEBUG_MSG("onGPSChanged() pos@%x:4, time=%u, lat=%d, bat=%d\n",
|
||||
pos.pos_timestamp, pos.time, pos.latitude_i, pos.battery_level);
|
||||
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.time, pos.latitude_i, pos.battery_level);
|
||||
|
||||
// Update our current position in the local DB
|
||||
nodeDB.updatePosition(nodeDB.getNodeNum(), pos, RX_SRC_LOCAL);
|
||||
nodeDB.updatePosition(nodeDB.getNodeNum(), pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class MeshService
|
||||
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
|
||||
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
|
||||
/// cache
|
||||
void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL);
|
||||
void sendToMesh(MeshPacket *p);
|
||||
|
||||
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
|
||||
bool cancelSending(PacketId id);
|
||||
|
||||
@@ -15,15 +15,6 @@ typedef uint32_t PacketId; // A packet sequence number
|
||||
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
|
||||
#define ERRNO_DISABLED 34 // the itnerface is disabled
|
||||
|
||||
/*
|
||||
* Source of a received message
|
||||
*/
|
||||
enum RxSource {
|
||||
RX_SRC_LOCAL, // message was generated locally
|
||||
RX_SRC_RADIO, // message was received from radio mesh
|
||||
RX_SRC_USER // message was received from end-user device
|
||||
};
|
||||
|
||||
/**
|
||||
* the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket.
|
||||
*
|
||||
|
||||
@@ -125,11 +125,6 @@ void NodeDB::installDefaultRadioConfig()
|
||||
memset(&radioConfig, 0, sizeof(radioConfig));
|
||||
radioConfig.has_preferences = true;
|
||||
resetRadioConfig();
|
||||
|
||||
// for backward compat, default position flags are BAT+ALT+MSL (0x23 = 35)
|
||||
radioConfig.preferences.position_flags = (PositionFlags_POS_BATTERY |
|
||||
PositionFlags_POS_ALTITUDE | PositionFlags_POS_ALT_MSL);
|
||||
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultChannels()
|
||||
@@ -447,42 +442,25 @@ size_t NodeDB::getNumOnlineNodes()
|
||||
|
||||
/** Update position info for this node based on received position data
|
||||
*/
|
||||
void NodeDB::updatePosition(uint32_t nodeId, const Position &p, RxSource src)
|
||||
void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
|
||||
{
|
||||
NodeInfo *info = getOrCreateNode(nodeId);
|
||||
|
||||
if (src == RX_SRC_LOCAL) {
|
||||
// Local packet, fully authoritative
|
||||
DEBUG_MSG("updatePosition LOCAL pos@%x:5, time=%u, latI=%d, lonI=%d\n",
|
||||
p.pos_timestamp, p.time, p.latitude_i, p.longitude_i);
|
||||
info->position = p;
|
||||
DEBUG_MSG("DB update position node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||
|
||||
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.pos_timestamp &&
|
||||
!p.location_source) {
|
||||
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
|
||||
// (stop-gap fix for issue #900)
|
||||
DEBUG_MSG("updatePosition SPECIAL time setting time=%u\n", p.time);
|
||||
// Be careful to only update fields that have been set by the sender
|
||||
// A lot of position reports don't have time populated. In that case, be careful to not blow away the time we
|
||||
// recorded based on the packet rxTime
|
||||
if (p.time)
|
||||
info->position.time = p.time;
|
||||
|
||||
} else {
|
||||
// Be careful to only update fields that have been set by the REMOTE sender
|
||||
// A lot of position reports don't have time populated. In that case, be careful to not blow away the time we
|
||||
// recorded based on the packet rxTime
|
||||
//
|
||||
// FIXME perhaps handle RX_SRC_USER separately?
|
||||
DEBUG_MSG("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n",
|
||||
nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||
|
||||
// First, back up fields that we want to protect from overwrite
|
||||
uint32_t tmp_time = info->position.time;
|
||||
|
||||
// Next, update atomically
|
||||
info->position = p;
|
||||
|
||||
// Last, restore any fields that may have been overwritten
|
||||
if (! info->position.time)
|
||||
info->position.time = tmp_time;
|
||||
if (p.battery_level)
|
||||
info->position.battery_level = p.battery_level;
|
||||
if (p.latitude_i || p.longitude_i) {
|
||||
info->position.latitude_i = p.latitude_i;
|
||||
info->position.longitude_i = p.longitude_i;
|
||||
}
|
||||
if (p.altitude)
|
||||
info->position.altitude = p.altitude;
|
||||
info->has_position = true;
|
||||
updateGUIforNode = info;
|
||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||
|
||||
@@ -59,7 +59,7 @@ class NodeDB
|
||||
|
||||
/** Update position info for this node based on received position data
|
||||
*/
|
||||
void updatePosition(uint32_t nodeId, const Position &p, RxSource src = RX_SRC_RADIO);
|
||||
void updatePosition(uint32_t nodeId, const Position &p);
|
||||
|
||||
/** Update user info for this node based on received user data
|
||||
*/
|
||||
|
||||
@@ -49,9 +49,9 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
|
||||
private:
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp)
|
||||
virtual bool handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
// FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us
|
||||
// it would be better to update even if the message was destined to others.
|
||||
@@ -70,6 +70,6 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
|
||||
DEBUG_MSG("Error decoding protobuf plugin!\n");
|
||||
}
|
||||
|
||||
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;
|
||||
return handleReceivedProtobuf(mp, decoded);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,15 +67,9 @@ bool RF95Interface::init()
|
||||
#endif
|
||||
setTransmitEnable(false);
|
||||
|
||||
int res = lora->begin(getFreq(), bw, sf, cr, syncWord, power, currentLimit, preambleLength);
|
||||
int res = lora->begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength);
|
||||
DEBUG_MSG("RF95 init result %d\n", res);
|
||||
|
||||
// current limit was removed from module' ctor
|
||||
// override default value (60 mA)
|
||||
res = lora->setCurrentLimit(currentLimit);
|
||||
DEBUG_MSG("Current limit set to %f\n", currentLimit);
|
||||
DEBUG_MSG("Current limit set result %d\n", res);
|
||||
|
||||
if (res == ERR_NONE)
|
||||
res = lora->setCRC(SX126X_LORA_CRC_ON);
|
||||
|
||||
@@ -119,7 +113,7 @@ bool RF95Interface::reconfigure()
|
||||
err = lora->setPreambleLength(preambleLength);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora->setFrequency(getFreq());
|
||||
err = lora->setFrequency(freq);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
|
||||
@@ -307,8 +307,6 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
if (bw == 31) // This parameter is not an integer
|
||||
bw = 31.25;
|
||||
if (bw == 62) // Fix for 62.5Khz bandwidth
|
||||
bw = 62.5;
|
||||
}
|
||||
|
||||
power = channelSettings.tx_power;
|
||||
@@ -320,18 +318,18 @@ void RadioInterface::applyModemConfig()
|
||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
||||
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels;
|
||||
float freq = myRegion->freq + radioConfig.preferences.frequency_offset + myRegion->spacing * channel_num;
|
||||
|
||||
saveChannelNum(channel_num);
|
||||
saveFreq(freq);
|
||||
freq = myRegion->freq + radioConfig.preferences.frequency_offset + myRegion->spacing * channel_num;
|
||||
|
||||
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
|
||||
DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
|
||||
DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
|
||||
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", getFreq()); // the frequency could be overridden in RadioInterface::getFreq() for some modules
|
||||
DEBUG_MSG("Radio frequency: %f\n", freq);
|
||||
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
|
||||
|
||||
saveChannelNum(channel_num);
|
||||
saveFreq(freq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,6 +78,8 @@ class RadioInterface
|
||||
void deliverToReceiver(MeshPacket *p);
|
||||
|
||||
public:
|
||||
float freq = 915.0;
|
||||
|
||||
/** pool is the pool we will alloc our rx packets from
|
||||
*/
|
||||
RadioInterface();
|
||||
@@ -147,7 +149,7 @@ class RadioInterface
|
||||
/**
|
||||
* Get the frequency we saved.
|
||||
*/
|
||||
virtual float getFreq();
|
||||
float getFreq();
|
||||
|
||||
/// Some boards (1st gen Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||
virtual bool isIRQPending() { return false; }
|
||||
|
||||
@@ -87,8 +87,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
* for a long time.
|
||||
*/
|
||||
const uint8_t syncWord = 0x2b;
|
||||
|
||||
float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset.
|
||||
|
||||
float currentLimit = 100; // FIXME
|
||||
|
||||
LockingModule module; // The HW interface to the radio
|
||||
|
||||
|
||||
@@ -10,21 +10,15 @@
|
||||
|
||||
RadioLibRF95::RadioLibRF95(Module *mod) : SX1278(mod) {}
|
||||
|
||||
int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power,
|
||||
int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit,
|
||||
uint16_t preambleLength, uint8_t gain)
|
||||
{
|
||||
// execute common part
|
||||
int16_t state = SX127x::begin(RF95_CHIP_VERSION, syncWord, preambleLength);
|
||||
int16_t state = SX127x::begin(RF95_CHIP_VERSION, syncWord, currentLimit, preambleLength);
|
||||
if (state != ERR_NONE)
|
||||
state = SX127x::begin(RF95_ALT_VERSION, syncWord, preambleLength);
|
||||
state = SX127x::begin(RF95_ALT_VERSION, syncWord, currentLimit, preambleLength);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// current limit was removed from module' ctor
|
||||
// override default value (60 mA)
|
||||
state = setCurrentLimit(currentLimit);
|
||||
DEBUG_MSG("Current limit set to %f\n", currentLimit);
|
||||
DEBUG_MSG("Current limit set result %d\n", state);
|
||||
|
||||
// configure settings not accessible by API
|
||||
state = config();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
@@ -35,6 +35,9 @@ class RadioLibRF95: public SX1278 {
|
||||
|
||||
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
Set to 0 to disable OCP (not recommended).
|
||||
|
||||
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
|
||||
Allowed values range from 6 to 65535.
|
||||
|
||||
@@ -43,7 +46,7 @@ class RadioLibRF95: public SX1278 {
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint16_t preambleLength = 8, uint8_t gain = 0);
|
||||
int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
|
||||
|
||||
// configuration methods
|
||||
|
||||
@@ -62,11 +65,6 @@ class RadioLibRF95: public SX1278 {
|
||||
/// For debugging
|
||||
uint8_t readReg(uint8_t addr);
|
||||
|
||||
protected:
|
||||
// since default current limit for SX126x/127x in updated RadioLib is 60mA
|
||||
// use the previous value
|
||||
float currentLimit = 100;
|
||||
|
||||
#ifndef RADIOLIB_GODMODE
|
||||
private:
|
||||
#endif
|
||||
|
||||
@@ -26,7 +26,7 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
|
||||
return FloodingRouter::send(p);
|
||||
}
|
||||
|
||||
bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
{
|
||||
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
|
||||
if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) {
|
||||
@@ -54,17 +54,6 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
}
|
||||
}
|
||||
|
||||
/* send acks for repeated packets that want acks and are destined for us
|
||||
* this way if an ACK is dropped and a packet is resent we'll ACK the resent packet
|
||||
* make sure wasSeenRecently _doesn't_ update
|
||||
* finding the channel requires decoding the packet. */
|
||||
if (p->want_ack && (p->to == getNodeNum()) && wasSeenRecently(p, false)) {
|
||||
if (perhapsDecode(p)) {
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
DEBUG_MSG("acking a repeated want_ack packet\n");
|
||||
}
|
||||
}
|
||||
|
||||
return FloodingRouter::shouldFilterReceived(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class ReliableRouter : public FloodingRouter
|
||||
/**
|
||||
* We hook this method so we can see packets before FloodingRouter says they should be discarded
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p);
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p);
|
||||
|
||||
/**
|
||||
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.
|
||||
|
||||
@@ -145,7 +145,7 @@ void Router::setReceivedMessage()
|
||||
runASAP = true;
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p, RxSource src)
|
||||
ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
{
|
||||
// No need to deliver externally if the destination is the local node
|
||||
if (p->to == nodeDB.getNodeNum()) {
|
||||
@@ -161,7 +161,7 @@ ErrorCode Router::sendLocal(MeshPacket *p, RxSource src)
|
||||
// If we are sending a broadcast, we also treat it as if we just received it ourself
|
||||
// this allows local apps (and PCs) to see broadcasts sourced locally
|
||||
if (p->to == NODENUM_BROADCAST) {
|
||||
handleReceived(p, src);
|
||||
handleReceived(p);
|
||||
}
|
||||
|
||||
return send(p);
|
||||
@@ -324,7 +324,7 @@ NodeNum Router::getNodeNum()
|
||||
* Handle any packet that is received by an interface on this node.
|
||||
* Note: some packets may merely being passed through this node and will be forwarded elsewhere.
|
||||
*/
|
||||
void Router::handleReceived(MeshPacket *p, RxSource src)
|
||||
void Router::handleReceived(MeshPacket *p)
|
||||
{
|
||||
// Also, we should set the time from the ISR and it should have msec level resolution
|
||||
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
||||
@@ -333,18 +333,13 @@ void Router::handleReceived(MeshPacket *p, RxSource src)
|
||||
bool decoded = perhapsDecode(p);
|
||||
if (decoded) {
|
||||
// parsing was successful, queue for our recipient
|
||||
if (src == RX_SRC_LOCAL)
|
||||
printPacket("handleReceived(LOCAL)", p);
|
||||
else if (src == RX_SRC_USER)
|
||||
printPacket("handleReceived(USER)", p);
|
||||
else
|
||||
printPacket("handleReceived(REMOTE)", p);
|
||||
printPacket("handleReceived", p);
|
||||
} else {
|
||||
printPacket("packet decoding failed (no PSK?)", p);
|
||||
}
|
||||
|
||||
// call plugins here
|
||||
MeshPlugin::callPlugins(*p, src);
|
||||
MeshPlugin::callPlugins(*p);
|
||||
}
|
||||
|
||||
void Router::perhapsHandleReceived(MeshPacket *p)
|
||||
|
||||
@@ -45,7 +45,7 @@ class Router : protected concurrency::OSThread
|
||||
*
|
||||
* NOTE: This method will free the provided packet (even if we return an error code)
|
||||
*/
|
||||
ErrorCode sendLocal(MeshPacket *p, RxSource src = RX_SRC_RADIO);
|
||||
ErrorCode sendLocal(MeshPacket *p);
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
bool cancelSending(NodeNum from, PacketId id);
|
||||
@@ -90,7 +90,7 @@ class Router : protected concurrency::OSThread
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) { return false; }
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p) { return false; }
|
||||
|
||||
/**
|
||||
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
|
||||
@@ -122,7 +122,7 @@ class Router : protected concurrency::OSThread
|
||||
* Note: this packet will never be called for messages sent/generated by this node.
|
||||
* Note: this method will free the provided packet.
|
||||
*/
|
||||
void handleReceived(MeshPacket *p, RxSource src = RX_SRC_RADIO);
|
||||
void handleReceived(MeshPacket *p);
|
||||
|
||||
/** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */
|
||||
void abortSendAndNak(Routing_Error err, MeshPacket *p);
|
||||
|
||||
@@ -2,8 +2,250 @@
|
||||
#include "SX1262Interface.h"
|
||||
#include "error.h"
|
||||
|
||||
// Particular boards might define a different max power based on what their hardware can do
|
||||
#ifndef SX1262_MAX_POWER
|
||||
#define SX1262_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
SX1262Interface::SX1262Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
|
||||
SPIClass &spi)
|
||||
: SX126xInterface(cs, irq, rst, busy, spi)
|
||||
: RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module)
|
||||
{
|
||||
}
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
bool SX1262Interface::init()
|
||||
{
|
||||
#ifdef SX1262_POWER_EN
|
||||
digitalWrite(SX1262_POWER_EN, HIGH);
|
||||
pinMode(SX1262_POWER_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef SX1262_RXEN // set not rx or tx mode
|
||||
digitalWrite(SX1262_RXEN, LOW); // Set low before becoming an output
|
||||
pinMode(SX1262_RXEN, OUTPUT);
|
||||
#endif
|
||||
#ifdef SX1262_TXEN
|
||||
digitalWrite(SX1262_TXEN, LOW);
|
||||
pinMode(SX1262_TXEN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifndef SX1262_E22
|
||||
float tcxoVoltage = 0; // None - we use an XTAL
|
||||
#else
|
||||
// Use DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
|
||||
float tcxoVoltage = 1.8;
|
||||
#endif
|
||||
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
|
||||
|
||||
RadioLibInterface::init();
|
||||
|
||||
if (power == 0)
|
||||
power = SX1262_MAX_POWER;
|
||||
|
||||
if (power > SX1262_MAX_POWER) // This chip has lower power limits than some
|
||||
power = SX1262_MAX_POWER;
|
||||
|
||||
limitPower();
|
||||
|
||||
int res = lora.begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO);
|
||||
DEBUG_MSG("SX1262 init result %d\n", res);
|
||||
|
||||
#ifdef SX1262_TXEN
|
||||
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
|
||||
if (res == ERR_NONE)
|
||||
res = lora.setDio2AsRfSwitch(false);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Read/write a register we are not using (only used for FSK mode) to test SPI comms
|
||||
uint8_t crcLSB = 0;
|
||||
int err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
//if(crcLSB != 0x0f)
|
||||
// RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
crcLSB = 0x5a;
|
||||
err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
if(crcLSB != 0x5a)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
// If we got this far register accesses (and therefore SPI comms) are good
|
||||
#endif
|
||||
|
||||
if (res == ERR_NONE)
|
||||
res = lora.setCRC(SX126X_LORA_CRC_ON);
|
||||
|
||||
if (res == ERR_NONE)
|
||||
startReceive(); // start receiving
|
||||
|
||||
return res == ERR_NONE;
|
||||
}
|
||||
|
||||
bool SX1262Interface::reconfigure()
|
||||
{
|
||||
RadioLibInterface::reconfigure();
|
||||
|
||||
// set mode to standby
|
||||
setStandby();
|
||||
|
||||
// configure publicly accessible settings
|
||||
int err = lora.setSpreadingFactor(sf);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setBandwidth(bw);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setCodingRate(cr);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
|
||||
err = lora.setRxGain(true);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setSyncWord(syncWord);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setCurrentLimit(currentLimit);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setPreambleLength(preambleLength);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setFrequency(freq);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
err = lora.setOutputPower(power);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
startReceive(); // restart receiving
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
void INTERRUPT_ATTR SX1262Interface::disableInterrupt()
|
||||
{
|
||||
lora.clearDio1Action();
|
||||
}
|
||||
|
||||
void SX1262Interface::setStandby()
|
||||
{
|
||||
checkNotification(); // handle any pending interrupts before we force standby
|
||||
|
||||
int err = lora.standby();
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
#ifdef SX1262_RXEN // we have RXEN/TXEN control - turn off RX and TX power
|
||||
digitalWrite(SX1262_RXEN, LOW);
|
||||
#endif
|
||||
#ifdef SX1262_TXEN
|
||||
digitalWrite(SX1262_TXEN, LOW);
|
||||
#endif
|
||||
|
||||
isReceiving = false; // If we were receiving, not any more
|
||||
disableInterrupt();
|
||||
completeSending(); // If we were sending, not anymore
|
||||
}
|
||||
|
||||
/**
|
||||
* Add SNR data to received messages
|
||||
*/
|
||||
void SX1262Interface::addReceiveMetadata(MeshPacket *mp)
|
||||
{
|
||||
// DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
}
|
||||
|
||||
/** We override to turn on transmitter power as needed.
|
||||
*/
|
||||
void SX1262Interface::configHardwareForSend()
|
||||
{
|
||||
#ifdef SX1262_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
|
||||
digitalWrite(SX1262_TXEN, HIGH);
|
||||
#endif
|
||||
|
||||
RadioLibInterface::configHardwareForSend();
|
||||
}
|
||||
|
||||
// For power draw measurements, helpful to force radio to stay sleeping
|
||||
// #define SLEEP_ONLY
|
||||
|
||||
void SX1262Interface::startReceive()
|
||||
{
|
||||
#ifdef SLEEP_ONLY
|
||||
sleep();
|
||||
#else
|
||||
|
||||
setStandby();
|
||||
|
||||
#ifdef SX1262_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
|
||||
digitalWrite(SX1262_RXEN, HIGH);
|
||||
#endif
|
||||
|
||||
// int err = lora.startReceive();
|
||||
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in
|
||||
// standby mostly.
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
isReceiving = true;
|
||||
|
||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
|
||||
enableInterrupt(isrRxLevel0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
bool SX1262Interface::isActivelyReceiving()
|
||||
{
|
||||
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
|
||||
// received and handled the interrupt for reading the packet/handling errors.
|
||||
// FIXME: it would be better to check for preamble, but we currently have our ISR not set to fire for packets that
|
||||
// never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network.
|
||||
|
||||
uint16_t irq = lora.getIrqStatus();
|
||||
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
|
||||
|
||||
// this is not correct - often always true - need to add an extra conditional
|
||||
// size_t bytesPending = lora.getPacketLength();
|
||||
|
||||
// if (hasPreamble) DEBUG_MSG("rx hasPreamble\n");
|
||||
return hasPreamble;
|
||||
}
|
||||
|
||||
bool SX1262Interface::sleep()
|
||||
{
|
||||
// Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
|
||||
DEBUG_MSG("sx1262 entering sleep mode (FIXME, don't keep config)\n");
|
||||
setStandby(); // Stop any pending operations
|
||||
|
||||
// turn off TCXO if it was powered
|
||||
// FIXME - this isn't correct
|
||||
// lora.setTCXO(0);
|
||||
|
||||
// put chipset into sleep mode (we've already disabled interrupts by now)
|
||||
bool keepConfig = true;
|
||||
lora.sleep(keepConfig); // Note: we do not keep the config, full reinit will be needed
|
||||
|
||||
#ifdef SX1262_POWER_EN
|
||||
digitalWrite(SX1262_POWER_EN, LOW);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,12 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "SX126xInterface.h"
|
||||
#include "RadioLibInterface.h"
|
||||
|
||||
/**
|
||||
* Our adapter for SX1262 radios
|
||||
*/
|
||||
class SX1262Interface : public SX126xInterface<SX1262>
|
||||
class SX1262Interface : public RadioLibInterface
|
||||
{
|
||||
SX1262 lora;
|
||||
|
||||
public:
|
||||
SX1262Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool init();
|
||||
|
||||
/// Apply any radio provisioning changes
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool reconfigure();
|
||||
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep();
|
||||
|
||||
bool isIRQPending() { return lora.getIrqStatus() != 0; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Glue functions called from ISR land
|
||||
*/
|
||||
virtual void disableInterrupt();
|
||||
|
||||
/**
|
||||
* Enable a particular ISR callback glue function
|
||||
*/
|
||||
virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); }
|
||||
|
||||
/** are we actively receiving a packet (only called during receiving state) */
|
||||
virtual bool isActivelyReceiving();
|
||||
|
||||
/**
|
||||
* Start waiting to receive a message
|
||||
*/
|
||||
virtual void startReceive();
|
||||
|
||||
/**
|
||||
* We override to turn on transmitter power as needed.
|
||||
*/
|
||||
virtual void configHardwareForSend();
|
||||
|
||||
/**
|
||||
* Add SNR data to received messages
|
||||
*/
|
||||
virtual void addReceiveMetadata(MeshPacket *mp);
|
||||
|
||||
virtual void setStandby();
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "configuration.h"
|
||||
#include "SX1268Interface.h"
|
||||
#include "error.h"
|
||||
|
||||
SX1268Interface::SX1268Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
|
||||
SPIClass &spi)
|
||||
: SX126xInterface(cs, irq, rst, busy, spi)
|
||||
{
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "SX126xInterface.h"
|
||||
|
||||
/**
|
||||
* Our adapter for SX1268 radios
|
||||
*/
|
||||
class SX1268Interface : public SX126xInterface<SX1268>
|
||||
{
|
||||
public:
|
||||
/// override frequency of the SX1268 module regardless of the region (use EU433 value)
|
||||
virtual float getFreq() { return 433.175f; }
|
||||
|
||||
SX1268Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
|
||||
};
|
||||
@@ -1,269 +0,0 @@
|
||||
#include "configuration.h"
|
||||
#include "SX126xInterface.h"
|
||||
#include "error.h"
|
||||
|
||||
// Particular boards might define a different max power based on what their hardware can do
|
||||
#ifndef SX126X_MAX_POWER
|
||||
#define SX126X_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
SX126xInterface<T>::SX126xInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
|
||||
SPIClass &spi)
|
||||
: RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module)
|
||||
{
|
||||
}
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
template<typename T>
|
||||
bool SX126xInterface<T>::init()
|
||||
{
|
||||
#ifdef SX126X_POWER_EN
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef SX126X_RXEN // set not rx or tx mode
|
||||
digitalWrite(SX126X_RXEN, LOW); // Set low before becoming an output
|
||||
pinMode(SX126X_RXEN, OUTPUT);
|
||||
#endif
|
||||
#ifdef SX126X_TXEN
|
||||
digitalWrite(SX126X_TXEN, LOW);
|
||||
pinMode(SX126X_TXEN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_E22
|
||||
float tcxoVoltage = 0; // None - we use an XTAL
|
||||
#else
|
||||
// Use DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
|
||||
float tcxoVoltage = 1.8;
|
||||
#endif
|
||||
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
|
||||
|
||||
RadioLibInterface::init();
|
||||
|
||||
if (power == 0)
|
||||
power = SX126X_MAX_POWER;
|
||||
|
||||
if (power > SX126X_MAX_POWER) // This chip has lower power limits than some
|
||||
power = SX126X_MAX_POWER;
|
||||
|
||||
limitPower();
|
||||
|
||||
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO);
|
||||
// \todo Display actual typename of the adapter, not just `SX126x`
|
||||
DEBUG_MSG("SX126x init result %d\n", res);
|
||||
|
||||
// current limit was removed from module' ctor
|
||||
// override default value (60 mA)
|
||||
res = lora.setCurrentLimit(currentLimit);
|
||||
DEBUG_MSG("Current limit set to %f\n", currentLimit);
|
||||
DEBUG_MSG("Current limit set result %d\n", res);
|
||||
|
||||
#ifdef SX126X_TXEN
|
||||
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
|
||||
if (res == ERR_NONE)
|
||||
res = lora.setDio2AsRfSwitch(false);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Read/write a register we are not using (only used for FSK mode) to test SPI comms
|
||||
uint8_t crcLSB = 0;
|
||||
int err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
//if(crcLSB != 0x0f)
|
||||
// RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
crcLSB = 0x5a;
|
||||
err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
if(crcLSB != 0x5a)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
// If we got this far register accesses (and therefore SPI comms) are good
|
||||
#endif
|
||||
|
||||
if (res == ERR_NONE)
|
||||
res = lora.setCRC(SX126X_LORA_CRC_ON);
|
||||
|
||||
if (res == ERR_NONE)
|
||||
startReceive(); // start receiving
|
||||
|
||||
return res == ERR_NONE;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool SX126xInterface<T>::reconfigure()
|
||||
{
|
||||
RadioLibInterface::reconfigure();
|
||||
|
||||
// set mode to standby
|
||||
setStandby();
|
||||
|
||||
// configure publicly accessible settings
|
||||
int err = lora.setSpreadingFactor(sf);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setBandwidth(bw);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setCodingRate(cr);
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
|
||||
err = lora.setRxGain(true);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setSyncWord(syncWord);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setCurrentLimit(currentLimit);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setPreambleLength(preambleLength);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setFrequency(getFreq());
|
||||
if (err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
err = lora.setOutputPower(power);
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
startReceive(); // restart receiving
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void INTERRUPT_ATTR SX126xInterface<T>::disableInterrupt()
|
||||
{
|
||||
lora.clearDio1Action();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SX126xInterface<T>::setStandby()
|
||||
{
|
||||
checkNotification(); // handle any pending interrupts before we force standby
|
||||
|
||||
int err = lora.standby();
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn off RX and TX power
|
||||
digitalWrite(SX126X_RXEN, LOW);
|
||||
#endif
|
||||
#ifdef SX126X_TXEN
|
||||
digitalWrite(SX126X_TXEN, LOW);
|
||||
#endif
|
||||
|
||||
isReceiving = false; // If we were receiving, not any more
|
||||
disableInterrupt();
|
||||
completeSending(); // If we were sending, not anymore
|
||||
}
|
||||
|
||||
/**
|
||||
* Add SNR data to received messages
|
||||
*/
|
||||
template<typename T>
|
||||
void SX126xInterface<T>::addReceiveMetadata(MeshPacket *mp)
|
||||
{
|
||||
// DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
}
|
||||
|
||||
/** We override to turn on transmitter power as needed.
|
||||
*/
|
||||
template<typename T>
|
||||
void SX126xInterface<T>::configHardwareForSend()
|
||||
{
|
||||
#ifdef SX126X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
|
||||
digitalWrite(SX126X_TXEN, HIGH);
|
||||
#endif
|
||||
|
||||
RadioLibInterface::configHardwareForSend();
|
||||
}
|
||||
|
||||
// For power draw measurements, helpful to force radio to stay sleeping
|
||||
// #define SLEEP_ONLY
|
||||
|
||||
template<typename T>
|
||||
void SX126xInterface<T>::startReceive()
|
||||
{
|
||||
#ifdef SLEEP_ONLY
|
||||
sleep();
|
||||
#else
|
||||
|
||||
setStandby();
|
||||
|
||||
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
|
||||
digitalWrite(SX126X_RXEN, HIGH);
|
||||
#endif
|
||||
|
||||
// int err = lora.startReceive();
|
||||
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in
|
||||
// standby mostly.
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
isReceiving = true;
|
||||
|
||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
|
||||
enableInterrupt(isrRxLevel0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
template<typename T>
|
||||
bool SX126xInterface<T>::isActivelyReceiving()
|
||||
{
|
||||
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
|
||||
// received and handled the interrupt for reading the packet/handling errors.
|
||||
// FIXME: it would be better to check for preamble, but we currently have our ISR not set to fire for packets that
|
||||
// never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network.
|
||||
|
||||
uint16_t irq = lora.getIrqStatus();
|
||||
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
|
||||
|
||||
// this is not correct - often always true - need to add an extra conditional
|
||||
// size_t bytesPending = lora.getPacketLength();
|
||||
|
||||
// if (hasPreamble) DEBUG_MSG("rx hasPreamble\n");
|
||||
return hasPreamble;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool SX126xInterface<T>::sleep()
|
||||
{
|
||||
// Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
|
||||
// \todo Display actual typename of the adapter, not just `SX126x`
|
||||
DEBUG_MSG("sx126x entering sleep mode (FIXME, don't keep config)\n");
|
||||
setStandby(); // Stop any pending operations
|
||||
|
||||
// turn off TCXO if it was powered
|
||||
// FIXME - this isn't correct
|
||||
// lora.setTCXO(0);
|
||||
|
||||
// put chipset into sleep mode (we've already disabled interrupts by now)
|
||||
bool keepConfig = true;
|
||||
lora.sleep(keepConfig); // Note: we do not keep the config, full reinit will be needed
|
||||
|
||||
#ifdef SX126X_POWER_EN
|
||||
digitalWrite(SX126X_POWER_EN, LOW);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RadioLibInterface.h"
|
||||
|
||||
/**
|
||||
* \brief Adapter for SX126x radio family. Implements common logic for child classes.
|
||||
* \tparam T RadioLib module type for SX126x: SX1262, SX1268.
|
||||
*/
|
||||
template<class T>
|
||||
class SX126xInterface : public RadioLibInterface
|
||||
{
|
||||
public:
|
||||
SX126xInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool init();
|
||||
|
||||
/// Apply any radio provisioning changes
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool reconfigure();
|
||||
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep();
|
||||
|
||||
bool isIRQPending() { return lora.getIrqStatus() != 0; }
|
||||
|
||||
protected:
|
||||
|
||||
float currentLimit = 140; // Higher OCP limit for SX126x PA
|
||||
|
||||
/**
|
||||
* Specific module instance
|
||||
*/
|
||||
T lora;
|
||||
|
||||
/**
|
||||
* Glue functions called from ISR land
|
||||
*/
|
||||
virtual void disableInterrupt();
|
||||
|
||||
/**
|
||||
* Enable a particular ISR callback glue function
|
||||
*/
|
||||
virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); }
|
||||
|
||||
/** are we actively receiving a packet (only called during receiving state) */
|
||||
virtual bool isActivelyReceiving();
|
||||
|
||||
/**
|
||||
* Start waiting to receive a message
|
||||
*/
|
||||
virtual void startReceive();
|
||||
|
||||
/**
|
||||
* We override to turn on transmitter power as needed.
|
||||
*/
|
||||
virtual void configHardwareForSend();
|
||||
|
||||
/**
|
||||
* Add SNR data to received messages
|
||||
*/
|
||||
virtual void addReceiveMetadata(MeshPacket *mp);
|
||||
|
||||
virtual void setStandby();
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -4,9 +4,9 @@
|
||||
#ifndef PB_ADMIN_PB_H_INCLUDED
|
||||
#define PB_ADMIN_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
#include "channel.pb.h"
|
||||
#include "mesh.pb.h"
|
||||
#include "radioconfig.pb.h"
|
||||
#include "channel.pb.h"
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
@@ -79,7 +79,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
|
||||
#define AdminMessage_fields &AdminMessage_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define AdminMessage_size 447
|
||||
#define AdminMessage_size 397
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -12,7 +12,7 @@ PB_BIND(LegacyRadioConfig, LegacyRadioConfig, AUTO)
|
||||
PB_BIND(LegacyRadioConfig_LegacyPreferences, LegacyRadioConfig_LegacyPreferences, AUTO)
|
||||
|
||||
|
||||
PB_BIND(DeviceState, DeviceState, 4)
|
||||
PB_BIND(DeviceState, DeviceState, 2)
|
||||
|
||||
|
||||
PB_BIND(ChannelFile, ChannelFile, 2)
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#ifndef PB_DEVICEONLY_PB_H_INCLUDED
|
||||
#define PB_DEVICEONLY_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
#include "channel.pb.h"
|
||||
#include "mesh.pb.h"
|
||||
#include "channel.pb.h"
|
||||
#include "radioconfig.pb.h"
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
@@ -125,7 +125,7 @@ extern const pb_msgdesc_t ChannelFile_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define LegacyRadioConfig_size 4
|
||||
#define LegacyRadioConfig_LegacyPreferences_size 2
|
||||
#define DeviceState_size 9594
|
||||
#define DeviceState_size 5190
|
||||
#define ChannelFile_size 832
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -49,6 +49,3 @@ PB_BIND(ToRadio_PeerInfo, ToRadio_PeerInfo, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -29,28 +29,9 @@ typedef enum _HardwareModel {
|
||||
HardwareModel_GENIEBLOCKS = 35,
|
||||
HardwareModel_NRF52_UNKNOWN = 36,
|
||||
HardwareModel_PORTDUINO = 37,
|
||||
HardwareModel_ANDROID_SIM = 38,
|
||||
HardwareModel_DIY_V1 = 39
|
||||
HardwareModel_ANDROID_SIM = 38
|
||||
} HardwareModel;
|
||||
|
||||
typedef enum _Team {
|
||||
Team_CLEAR = 0,
|
||||
Team_CYAN = 1,
|
||||
Team_WHITE = 2,
|
||||
Team_YELLOW = 3,
|
||||
Team_ORANGE = 4,
|
||||
Team_MAGENTA = 5,
|
||||
Team_RED = 6,
|
||||
Team_MAROON = 7,
|
||||
Team_PURPLE = 8,
|
||||
Team_DARK_BLUE = 9,
|
||||
Team_BLUE = 10,
|
||||
Team_TEAL = 11,
|
||||
Team_GREEN = 12,
|
||||
Team_DARK_GREEN = 13,
|
||||
Team_BROWN = 14
|
||||
} Team;
|
||||
|
||||
typedef enum _Constants {
|
||||
Constants_Unused = 0,
|
||||
Constants_DATA_PAYLOAD_LEN = 237
|
||||
@@ -71,21 +52,6 @@ typedef enum _CriticalErrorCode {
|
||||
CriticalErrorCode_RadioSpiBug = 11
|
||||
} CriticalErrorCode;
|
||||
|
||||
typedef enum _Position_LocSource {
|
||||
Position_LocSource_LOCSRC_UNSPECIFIED = 0,
|
||||
Position_LocSource_LOCSRC_MANUAL_ENTRY = 1,
|
||||
Position_LocSource_LOCSRC_GPS_INTERNAL = 2,
|
||||
Position_LocSource_LOCSRC_GPS_EXTERNAL = 3
|
||||
} Position_LocSource;
|
||||
|
||||
typedef enum _Position_AltSource {
|
||||
Position_AltSource_ALTSRC_UNSPECIFIED = 0,
|
||||
Position_AltSource_ALTSRC_MANUAL_ENTRY = 1,
|
||||
Position_AltSource_ALTSRC_GPS_INTERNAL = 2,
|
||||
Position_AltSource_ALTSRC_GPS_EXTERNAL = 3,
|
||||
Position_AltSource_ALTSRC_BAROMETRIC = 4
|
||||
} Position_AltSource;
|
||||
|
||||
typedef enum _Routing_Error {
|
||||
Routing_Error_NONE = 0,
|
||||
Routing_Error_NO_ROUTE = 1,
|
||||
@@ -160,24 +126,6 @@ typedef struct _Position {
|
||||
int32_t altitude;
|
||||
int32_t battery_level;
|
||||
uint32_t time;
|
||||
Position_LocSource location_source;
|
||||
Position_AltSource altitude_source;
|
||||
uint32_t pos_timestamp;
|
||||
int32_t pos_time_millis;
|
||||
int32_t altitude_hae;
|
||||
int32_t alt_geoid_sep;
|
||||
uint32_t PDOP;
|
||||
uint32_t HDOP;
|
||||
uint32_t VDOP;
|
||||
uint32_t gps_accuracy;
|
||||
uint32_t ground_speed;
|
||||
uint32_t ground_track;
|
||||
uint32_t fix_quality;
|
||||
uint32_t fix_type;
|
||||
uint32_t sats_in_view;
|
||||
uint32_t sensor_id;
|
||||
uint32_t pos_next_update;
|
||||
uint32_t pos_seq_number;
|
||||
} Position;
|
||||
|
||||
typedef struct _RouteDiscovery {
|
||||
@@ -197,10 +145,6 @@ typedef struct _User {
|
||||
pb_byte_t macaddr[6];
|
||||
HardwareModel hw_model;
|
||||
bool is_licensed;
|
||||
Team team;
|
||||
uint32_t tx_power_dbm;
|
||||
uint32_t ant_gain_dbi;
|
||||
uint32_t ant_azimuth;
|
||||
} User;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
|
||||
@@ -267,12 +211,8 @@ typedef struct _ToRadio {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _HardwareModel_MIN HardwareModel_UNSET
|
||||
#define _HardwareModel_MAX HardwareModel_DIY_V1
|
||||
#define _HardwareModel_ARRAYSIZE ((HardwareModel)(HardwareModel_DIY_V1+1))
|
||||
|
||||
#define _Team_MIN Team_CLEAR
|
||||
#define _Team_MAX Team_BROWN
|
||||
#define _Team_ARRAYSIZE ((Team)(Team_BROWN+1))
|
||||
#define _HardwareModel_MAX HardwareModel_ANDROID_SIM
|
||||
#define _HardwareModel_ARRAYSIZE ((HardwareModel)(HardwareModel_ANDROID_SIM+1))
|
||||
|
||||
#define _Constants_MIN Constants_Unused
|
||||
#define _Constants_MAX Constants_DATA_PAYLOAD_LEN
|
||||
@@ -282,14 +222,6 @@ typedef struct _ToRadio {
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_RadioSpiBug
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_RadioSpiBug+1))
|
||||
|
||||
#define _Position_LocSource_MIN Position_LocSource_LOCSRC_UNSPECIFIED
|
||||
#define _Position_LocSource_MAX Position_LocSource_LOCSRC_GPS_EXTERNAL
|
||||
#define _Position_LocSource_ARRAYSIZE ((Position_LocSource)(Position_LocSource_LOCSRC_GPS_EXTERNAL+1))
|
||||
|
||||
#define _Position_AltSource_MIN Position_AltSource_ALTSRC_UNSPECIFIED
|
||||
#define _Position_AltSource_MAX Position_AltSource_ALTSRC_BAROMETRIC
|
||||
#define _Position_AltSource_ARRAYSIZE ((Position_AltSource)(Position_AltSource_ALTSRC_BAROMETRIC+1))
|
||||
|
||||
#define _Routing_Error_MIN Routing_Error_NONE
|
||||
#define _Routing_Error_MAX Routing_Error_NOT_AUTHORIZED
|
||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_NOT_AUTHORIZED+1))
|
||||
@@ -308,8 +240,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define Position_init_default {0, 0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define User_init_default {"", "", "", {0}, _HardwareModel_MIN, 0, _Team_MIN, 0, 0, 0}
|
||||
#define Position_init_default {0, 0, 0, 0, 0}
|
||||
#define User_init_default {"", "", "", {0}, _HardwareModel_MIN, 0}
|
||||
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define Routing_init_default {0, {RouteDiscovery_init_default}}
|
||||
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
||||
@@ -320,8 +252,8 @@ extern "C" {
|
||||
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
|
||||
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
||||
#define ToRadio_PeerInfo_init_default {0, 0}
|
||||
#define Position_init_zero {0, 0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define User_init_zero {"", "", "", {0}, _HardwareModel_MIN, 0, _Team_MIN, 0, 0, 0}
|
||||
#define Position_init_zero {0, 0, 0, 0, 0}
|
||||
#define User_init_zero {"", "", "", {0}, _HardwareModel_MIN, 0}
|
||||
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
|
||||
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
||||
@@ -362,24 +294,6 @@ extern "C" {
|
||||
#define Position_altitude_tag 3
|
||||
#define Position_battery_level_tag 4
|
||||
#define Position_time_tag 9
|
||||
#define Position_location_source_tag 10
|
||||
#define Position_altitude_source_tag 11
|
||||
#define Position_pos_timestamp_tag 12
|
||||
#define Position_pos_time_millis_tag 13
|
||||
#define Position_altitude_hae_tag 14
|
||||
#define Position_alt_geoid_sep_tag 15
|
||||
#define Position_PDOP_tag 16
|
||||
#define Position_HDOP_tag 17
|
||||
#define Position_VDOP_tag 18
|
||||
#define Position_gps_accuracy_tag 19
|
||||
#define Position_ground_speed_tag 20
|
||||
#define Position_ground_track_tag 21
|
||||
#define Position_fix_quality_tag 22
|
||||
#define Position_fix_type_tag 23
|
||||
#define Position_sats_in_view_tag 24
|
||||
#define Position_sensor_id_tag 25
|
||||
#define Position_pos_next_update_tag 40
|
||||
#define Position_pos_seq_number_tag 41
|
||||
#define RouteDiscovery_route_tag 2
|
||||
#define ToRadio_PeerInfo_app_version_tag 1
|
||||
#define ToRadio_PeerInfo_mqtt_gateway_tag 2
|
||||
@@ -389,10 +303,6 @@ extern "C" {
|
||||
#define User_macaddr_tag 4
|
||||
#define User_hw_model_tag 6
|
||||
#define User_is_licensed_tag 7
|
||||
#define User_team_tag 8
|
||||
#define User_tx_power_dbm_tag 10
|
||||
#define User_ant_gain_dbi_tag 11
|
||||
#define User_ant_azimuth_tag 12
|
||||
#define MeshPacket_from_tag 1
|
||||
#define MeshPacket_to_tag 2
|
||||
#define MeshPacket_channel_tag 3
|
||||
@@ -431,25 +341,7 @@ X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 1) \
|
||||
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 2) \
|
||||
X(a, STATIC, SINGULAR, INT32, altitude, 3) \
|
||||
X(a, STATIC, SINGULAR, INT32, battery_level, 4) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, time, 9) \
|
||||
X(a, STATIC, SINGULAR, UENUM, location_source, 10) \
|
||||
X(a, STATIC, SINGULAR, UENUM, altitude_source, 11) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, pos_timestamp, 12) \
|
||||
X(a, STATIC, SINGULAR, INT32, pos_time_millis, 13) \
|
||||
X(a, STATIC, SINGULAR, SINT32, altitude_hae, 14) \
|
||||
X(a, STATIC, SINGULAR, SINT32, alt_geoid_sep, 15) \
|
||||
X(a, STATIC, SINGULAR, UINT32, PDOP, 16) \
|
||||
X(a, STATIC, SINGULAR, UINT32, HDOP, 17) \
|
||||
X(a, STATIC, SINGULAR, UINT32, VDOP, 18) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_accuracy, 19) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ground_speed, 20) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ground_track, 21) \
|
||||
X(a, STATIC, SINGULAR, UINT32, fix_quality, 22) \
|
||||
X(a, STATIC, SINGULAR, UINT32, fix_type, 23) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sats_in_view, 24) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sensor_id, 25) \
|
||||
X(a, STATIC, SINGULAR, UINT32, pos_next_update, 40) \
|
||||
X(a, STATIC, SINGULAR, UINT32, pos_seq_number, 41)
|
||||
X(a, STATIC, SINGULAR, FIXED32, time, 9)
|
||||
#define Position_CALLBACK NULL
|
||||
#define Position_DEFAULT NULL
|
||||
|
||||
@@ -459,11 +351,7 @@ X(a, STATIC, SINGULAR, STRING, long_name, 2) \
|
||||
X(a, STATIC, SINGULAR, STRING, short_name, 3) \
|
||||
X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) \
|
||||
X(a, STATIC, SINGULAR, UENUM, hw_model, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_licensed, 7) \
|
||||
X(a, STATIC, SINGULAR, UENUM, team, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, tx_power_dbm, 10) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ant_gain_dbi, 11) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ant_azimuth, 12)
|
||||
X(a, STATIC, SINGULAR, BOOL, is_licensed, 7)
|
||||
#define User_CALLBACK NULL
|
||||
#define User_DEFAULT NULL
|
||||
|
||||
@@ -603,13 +491,13 @@ extern const pb_msgdesc_t ToRadio_PeerInfo_msg;
|
||||
#define ToRadio_PeerInfo_fields &ToRadio_PeerInfo_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define Position_size 153
|
||||
#define User_size 96
|
||||
#define Position_size 37
|
||||
#define User_size 76
|
||||
#define RouteDiscovery_size 40
|
||||
#define Routing_size 42
|
||||
#define Data_size 260
|
||||
#define MeshPacket_size 309
|
||||
#define NodeInfo_size 270
|
||||
#define NodeInfo_size 133
|
||||
#define MyNodeInfo_size 101
|
||||
#define LogRecord_size 81
|
||||
#define FromRadio_size 318
|
||||
|
||||
@@ -24,7 +24,6 @@ typedef enum _PortNum {
|
||||
PortNum_STORE_FORWARD_APP = 65,
|
||||
PortNum_RANGE_TEST_APP = 66,
|
||||
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67,
|
||||
PortNum_ZPS_APP = 68,
|
||||
PortNum_PRIVATE_APP = 256,
|
||||
PortNum_ATAK_FORWARDER = 257,
|
||||
PortNum_MAX = 511
|
||||
|
||||
@@ -18,5 +18,3 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,37 +51,14 @@ typedef enum _GpsOperation {
|
||||
GpsOperation_GpsOpDisabled = 4
|
||||
} GpsOperation;
|
||||
|
||||
typedef enum _GpsCoordinateFormat {
|
||||
GpsCoordinateFormat_GpsFormatDec = 0,
|
||||
GpsCoordinateFormat_GpsFormatDMS = 1,
|
||||
GpsCoordinateFormat_GpsFormatUTM = 2,
|
||||
GpsCoordinateFormat_GpsFormatMGRS = 3,
|
||||
GpsCoordinateFormat_GpsFormatOLC = 4,
|
||||
GpsCoordinateFormat_GpsFormatOSGR = 5
|
||||
} GpsCoordinateFormat;
|
||||
|
||||
typedef enum _LocationSharing {
|
||||
LocationSharing_LocUnset = 0,
|
||||
LocationSharing_LocEnabled = 1,
|
||||
LocationSharing_LocDisabled = 2
|
||||
} LocationSharing;
|
||||
|
||||
typedef enum _PositionFlags {
|
||||
PositionFlags_POS_UNDEFINED = 0,
|
||||
PositionFlags_POS_ALTITUDE = 1,
|
||||
PositionFlags_POS_ALT_MSL = 2,
|
||||
PositionFlags_POS_GEO_SEP = 4,
|
||||
PositionFlags_POS_DOP = 8,
|
||||
PositionFlags_POS_HVDOP = 16,
|
||||
PositionFlags_POS_BATTERY = 32,
|
||||
PositionFlags_POS_SATINVIEW = 64,
|
||||
PositionFlags_POS_SEQ_NOS = 128,
|
||||
PositionFlags_POS_TIMESTAMP = 256
|
||||
} PositionFlags;
|
||||
|
||||
typedef enum _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType {
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 = 0,
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20 = 1
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 = 0
|
||||
} RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -101,7 +78,6 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
bool wifi_ap_mode;
|
||||
RegionCode region;
|
||||
ChargeCurrent charge_current;
|
||||
bool position_broadcast_smart;
|
||||
LocationSharing location_share;
|
||||
GpsOperation gps_operation;
|
||||
uint32_t gps_update_interval;
|
||||
@@ -113,9 +89,6 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
float frequency_offset;
|
||||
char mqtt_server[32];
|
||||
bool mqtt_disabled;
|
||||
GpsCoordinateFormat gps_format;
|
||||
bool gps_accept_2d;
|
||||
uint32_t gps_max_dop;
|
||||
bool factory_reset;
|
||||
bool debug_log_enabled;
|
||||
pb_size_t ignore_incoming_count;
|
||||
@@ -136,8 +109,6 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
uint32_t range_test_plugin_sender;
|
||||
bool range_test_plugin_save;
|
||||
uint32_t store_forward_plugin_records;
|
||||
uint32_t store_forward_plugin_history_return_max;
|
||||
uint32_t store_forward_plugin_history_return_window;
|
||||
bool environmental_measurement_plugin_measurement_enabled;
|
||||
bool environmental_measurement_plugin_screen_enabled;
|
||||
uint32_t environmental_measurement_plugin_read_error_count_threshold;
|
||||
@@ -147,10 +118,6 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type;
|
||||
uint32_t environmental_measurement_plugin_sensor_pin;
|
||||
bool store_forward_plugin_enabled;
|
||||
bool store_forward_plugin_heartbeat;
|
||||
uint32_t position_flags;
|
||||
bool is_always_powered;
|
||||
uint32_t auto_screen_carousel_secs;
|
||||
} RadioConfig_UserPreferences;
|
||||
|
||||
typedef struct _RadioConfig {
|
||||
@@ -172,21 +139,13 @@ typedef struct _RadioConfig {
|
||||
#define _GpsOperation_MAX GpsOperation_GpsOpDisabled
|
||||
#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
|
||||
|
||||
#define _GpsCoordinateFormat_MIN GpsCoordinateFormat_GpsFormatDec
|
||||
#define _GpsCoordinateFormat_MAX GpsCoordinateFormat_GpsFormatOSGR
|
||||
#define _GpsCoordinateFormat_ARRAYSIZE ((GpsCoordinateFormat)(GpsCoordinateFormat_GpsFormatOSGR+1))
|
||||
|
||||
#define _LocationSharing_MIN LocationSharing_LocUnset
|
||||
#define _LocationSharing_MAX LocationSharing_LocDisabled
|
||||
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
|
||||
|
||||
#define _PositionFlags_MIN PositionFlags_POS_UNDEFINED
|
||||
#define _PositionFlags_MAX PositionFlags_POS_TIMESTAMP
|
||||
#define _PositionFlags_ARRAYSIZE ((PositionFlags)(PositionFlags_POS_TIMESTAMP+1))
|
||||
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20+1))
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
|
||||
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11+1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -195,9 +154,9 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
|
||||
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0}
|
||||
#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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
|
||||
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
|
||||
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0}
|
||||
#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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
||||
@@ -215,7 +174,6 @@ extern "C" {
|
||||
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
|
||||
#define RadioConfig_UserPreferences_region_tag 15
|
||||
#define RadioConfig_UserPreferences_charge_current_tag 16
|
||||
#define RadioConfig_UserPreferences_position_broadcast_smart_tag 17
|
||||
#define RadioConfig_UserPreferences_location_share_tag 32
|
||||
#define RadioConfig_UserPreferences_gps_operation_tag 33
|
||||
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
|
||||
@@ -227,9 +185,6 @@ extern "C" {
|
||||
#define RadioConfig_UserPreferences_frequency_offset_tag 41
|
||||
#define RadioConfig_UserPreferences_mqtt_server_tag 42
|
||||
#define RadioConfig_UserPreferences_mqtt_disabled_tag 43
|
||||
#define RadioConfig_UserPreferences_gps_format_tag 44
|
||||
#define RadioConfig_UserPreferences_gps_accept_2d_tag 45
|
||||
#define RadioConfig_UserPreferences_gps_max_dop_tag 46
|
||||
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
||||
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
|
||||
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
|
||||
@@ -249,8 +204,6 @@ extern "C" {
|
||||
#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133
|
||||
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_history_return_max_tag 138
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_history_return_window_tag 139
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142
|
||||
@@ -260,10 +213,6 @@ extern "C" {
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146
|
||||
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 148
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_heartbeat_tag 149
|
||||
#define RadioConfig_UserPreferences_position_flags_tag 150
|
||||
#define RadioConfig_UserPreferences_is_always_powered_tag 151
|
||||
#define RadioConfig_UserPreferences_auto_screen_carousel_secs_tag 152
|
||||
#define RadioConfig_preferences_tag 1
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
@@ -289,7 +238,6 @@ X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
|
||||
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
|
||||
X(a, STATIC, SINGULAR, UENUM, region, 15) \
|
||||
X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \
|
||||
X(a, STATIC, SINGULAR, BOOL, position_broadcast_smart, 17) \
|
||||
X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
|
||||
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
|
||||
@@ -301,9 +249,6 @@ X(a, STATIC, SINGULAR, BOOL, serial_disabled, 40) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, frequency_offset, 41) \
|
||||
X(a, STATIC, SINGULAR, STRING, mqtt_server, 42) \
|
||||
X(a, STATIC, SINGULAR, BOOL, mqtt_disabled, 43) \
|
||||
X(a, STATIC, SINGULAR, UENUM, gps_format, 44) \
|
||||
X(a, STATIC, SINGULAR, BOOL, gps_accept_2d, 45) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_max_dop, 46) \
|
||||
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
|
||||
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
|
||||
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
|
||||
@@ -323,8 +268,6 @@ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \
|
||||
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
|
||||
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
|
||||
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \
|
||||
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_history_return_max, 138) \
|
||||
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_history_return_window, 139) \
|
||||
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \
|
||||
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
|
||||
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \
|
||||
@@ -333,11 +276,7 @@ X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_int
|
||||
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \
|
||||
X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \
|
||||
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147) \
|
||||
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 148) \
|
||||
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_heartbeat, 149) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_flags, 150) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_always_powered, 151) \
|
||||
X(a, STATIC, SINGULAR, UINT32, auto_screen_carousel_secs, 152)
|
||||
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 148)
|
||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||
#define RadioConfig_UserPreferences_DEFAULT NULL
|
||||
|
||||
@@ -349,8 +288,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
|
||||
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define RadioConfig_size 444
|
||||
#define RadioConfig_UserPreferences_size 441
|
||||
#define RadioConfig_size 394
|
||||
#define RadioConfig_UserPreferences_size 391
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.4 */
|
||||
|
||||
#include "storeforward.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(StoreAndForward, StoreAndForward, AUTO)
|
||||
|
||||
|
||||
PB_BIND(StoreAndForward_Statistics, StoreAndForward_Statistics, AUTO)
|
||||
|
||||
|
||||
PB_BIND(StoreAndForward_History, StoreAndForward_History, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.4 */
|
||||
|
||||
#ifndef PB_STOREFORWARD_PB_H_INCLUDED
|
||||
#define PB_STOREFORWARD_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
/* Enum definitions */
|
||||
typedef enum _StoreAndForward_RequestResponse {
|
||||
StoreAndForward_RequestResponse_UNSET = 0,
|
||||
StoreAndForward_RequestResponse_ROUTER_ERROR = 1,
|
||||
StoreAndForward_RequestResponse_ROUTER_HEARTBEAT = 2,
|
||||
StoreAndForward_RequestResponse_ROUTER_PING = 3,
|
||||
StoreAndForward_RequestResponse_ROUTER_PONG = 4,
|
||||
StoreAndForward_RequestResponse_ROUTER_BUSY = 5,
|
||||
StoreAndForward_RequestResponse_CLIENT_ERROR = 101,
|
||||
StoreAndForward_RequestResponse_CLIENT_HISTORY = 102,
|
||||
StoreAndForward_RequestResponse_CLIENT_STATS = 103,
|
||||
StoreAndForward_RequestResponse_CLIENT_PING = 104,
|
||||
StoreAndForward_RequestResponse_CLIENT_PONG = 105
|
||||
} StoreAndForward_RequestResponse;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _StoreAndForward_History {
|
||||
uint32_t HistoryMessages;
|
||||
uint32_t Window;
|
||||
} StoreAndForward_History;
|
||||
|
||||
typedef struct _StoreAndForward_Statistics {
|
||||
uint32_t MessagesTotal;
|
||||
uint32_t MessagesSaved;
|
||||
uint32_t MessagesMax;
|
||||
uint32_t UpTime;
|
||||
uint32_t Requests;
|
||||
uint32_t RequestsHistory;
|
||||
bool Heartbeat;
|
||||
uint32_t ReturnMax;
|
||||
uint32_t ReturnWindow;
|
||||
} StoreAndForward_Statistics;
|
||||
|
||||
typedef struct _StoreAndForward {
|
||||
StoreAndForward_RequestResponse rr;
|
||||
bool has_stats;
|
||||
StoreAndForward_Statistics stats;
|
||||
bool has_history;
|
||||
StoreAndForward_History history;
|
||||
} StoreAndForward;
|
||||
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _StoreAndForward_RequestResponse_MIN StoreAndForward_RequestResponse_UNSET
|
||||
#define _StoreAndForward_RequestResponse_MAX StoreAndForward_RequestResponse_CLIENT_PONG
|
||||
#define _StoreAndForward_RequestResponse_ARRAYSIZE ((StoreAndForward_RequestResponse)(StoreAndForward_RequestResponse_CLIENT_PONG+1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define StoreAndForward_init_default {_StoreAndForward_RequestResponse_MIN, false, StoreAndForward_Statistics_init_default, false, StoreAndForward_History_init_default}
|
||||
#define StoreAndForward_Statistics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define StoreAndForward_History_init_default {0, 0}
|
||||
#define StoreAndForward_init_zero {_StoreAndForward_RequestResponse_MIN, false, StoreAndForward_Statistics_init_zero, false, StoreAndForward_History_init_zero}
|
||||
#define StoreAndForward_Statistics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define StoreAndForward_History_init_zero {0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define StoreAndForward_History_HistoryMessages_tag 1
|
||||
#define StoreAndForward_History_Window_tag 2
|
||||
#define StoreAndForward_Statistics_MessagesTotal_tag 1
|
||||
#define StoreAndForward_Statistics_MessagesSaved_tag 2
|
||||
#define StoreAndForward_Statistics_MessagesMax_tag 3
|
||||
#define StoreAndForward_Statistics_UpTime_tag 4
|
||||
#define StoreAndForward_Statistics_Requests_tag 5
|
||||
#define StoreAndForward_Statistics_RequestsHistory_tag 6
|
||||
#define StoreAndForward_Statistics_Heartbeat_tag 7
|
||||
#define StoreAndForward_Statistics_ReturnMax_tag 8
|
||||
#define StoreAndForward_Statistics_ReturnWindow_tag 9
|
||||
#define StoreAndForward_rr_tag 1
|
||||
#define StoreAndForward_stats_tag 2
|
||||
#define StoreAndForward_history_tag 3
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define StoreAndForward_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, rr, 1) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, stats, 2) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, history, 3)
|
||||
#define StoreAndForward_CALLBACK NULL
|
||||
#define StoreAndForward_DEFAULT NULL
|
||||
#define StoreAndForward_stats_MSGTYPE StoreAndForward_Statistics
|
||||
#define StoreAndForward_history_MSGTYPE StoreAndForward_History
|
||||
|
||||
#define StoreAndForward_Statistics_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, MessagesTotal, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, MessagesSaved, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, MessagesMax, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, UpTime, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, Requests, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, RequestsHistory, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, Heartbeat, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ReturnMax, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ReturnWindow, 9)
|
||||
#define StoreAndForward_Statistics_CALLBACK NULL
|
||||
#define StoreAndForward_Statistics_DEFAULT NULL
|
||||
|
||||
#define StoreAndForward_History_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, HistoryMessages, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, Window, 2)
|
||||
#define StoreAndForward_History_CALLBACK NULL
|
||||
#define StoreAndForward_History_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t StoreAndForward_msg;
|
||||
extern const pb_msgdesc_t StoreAndForward_Statistics_msg;
|
||||
extern const pb_msgdesc_t StoreAndForward_History_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define StoreAndForward_fields &StoreAndForward_msg
|
||||
#define StoreAndForward_Statistics_fields &StoreAndForward_Statistics_msg
|
||||
#define StoreAndForward_History_fields &StoreAndForward_History_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define StoreAndForward_size 68
|
||||
#define StoreAndForward_Statistics_size 50
|
||||
#define StoreAndForward_History_size 12
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "airtime.h"
|
||||
#include "main.h"
|
||||
#include "mesh/http/ContentHelper.h"
|
||||
#include "mesh/http/ContentStatic.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "power.h"
|
||||
#include "sleep.h"
|
||||
@@ -78,17 +79,19 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
|
||||
ResourceNode *nodeHotspotApple = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot);
|
||||
ResourceNode *nodeHotspotAndroid = new ResourceNode("/generate_204", "GET", &handleHotspot);
|
||||
|
||||
ResourceNode *nodeFavicon = new ResourceNode("/favicon.ico", "GET", &handleFavicon);
|
||||
ResourceNode *nodeRoot = new ResourceNode("/", "GET", &handleRoot);
|
||||
ResourceNode *nodeStaticBrowse = new ResourceNode("/static", "GET", &handleStaticBrowse);
|
||||
ResourceNode *nodeStaticPOST = new ResourceNode("/static", "POST", &handleStaticPost);
|
||||
ResourceNode *nodeStatic = new ResourceNode("/static/*", "GET", &handleStatic);
|
||||
ResourceNode *nodeRestart = new ResourceNode("/restart", "POST", &handleRestart);
|
||||
ResourceNode *node404 = new ResourceNode("", "GET", &handle404);
|
||||
ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
|
||||
|
||||
ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks);
|
||||
ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED);
|
||||
ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport);
|
||||
ResourceNode *nodeJsonSpiffsBrowseStatic = new ResourceNode("/json/spiffs/browse/static", "GET", &handleSpiffsBrowseStatic);
|
||||
ResourceNode *nodeJsonDelete = new ResourceNode("/json/spiffs/delete/static", "DELETE", &handleSpiffsDeleteStatic);
|
||||
|
||||
ResourceNode *nodeRoot = new ResourceNode("/*", "GET", &handleStatic);
|
||||
|
||||
// Secure nodes
|
||||
secureServer->registerNode(nodeAPIv1ToRadioOptions);
|
||||
@@ -96,6 +99,11 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
secureServer->registerNode(nodeAPIv1FromRadio);
|
||||
secureServer->registerNode(nodeHotspotApple);
|
||||
secureServer->registerNode(nodeHotspotAndroid);
|
||||
secureServer->registerNode(nodeFavicon);
|
||||
secureServer->registerNode(nodeRoot);
|
||||
secureServer->registerNode(nodeStaticBrowse);
|
||||
secureServer->registerNode(nodeStaticPOST);
|
||||
secureServer->registerNode(nodeStatic);
|
||||
secureServer->registerNode(nodeRestart);
|
||||
secureServer->registerNode(nodeFormUpload);
|
||||
secureServer->registerNode(nodeJsonScanNetworks);
|
||||
@@ -103,7 +111,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
secureServer->registerNode(nodeJsonSpiffsBrowseStatic);
|
||||
secureServer->registerNode(nodeJsonDelete);
|
||||
secureServer->registerNode(nodeJsonReport);
|
||||
secureServer->registerNode(nodeRoot);
|
||||
secureServer->setDefaultNode(node404);
|
||||
|
||||
secureServer->addMiddleware(&middlewareSpeedUp240);
|
||||
|
||||
@@ -113,6 +121,11 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
insecureServer->registerNode(nodeAPIv1FromRadio);
|
||||
insecureServer->registerNode(nodeHotspotApple);
|
||||
insecureServer->registerNode(nodeHotspotAndroid);
|
||||
insecureServer->registerNode(nodeFavicon);
|
||||
insecureServer->registerNode(nodeRoot);
|
||||
insecureServer->registerNode(nodeStaticBrowse);
|
||||
insecureServer->registerNode(nodeStaticPOST);
|
||||
insecureServer->registerNode(nodeStatic);
|
||||
insecureServer->registerNode(nodeRestart);
|
||||
insecureServer->registerNode(nodeFormUpload);
|
||||
insecureServer->registerNode(nodeJsonScanNetworks);
|
||||
@@ -120,7 +133,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
insecureServer->registerNode(nodeJsonSpiffsBrowseStatic);
|
||||
insecureServer->registerNode(nodeJsonDelete);
|
||||
insecureServer->registerNode(nodeJsonReport);
|
||||
insecureServer->registerNode(nodeRoot);
|
||||
insecureServer->setDefaultNode(node404);
|
||||
|
||||
insecureServer->addMiddleware(&middlewareSpeedUp160);
|
||||
}
|
||||
@@ -167,8 +180,11 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
/*
|
||||
For documentation, see:
|
||||
https://meshtastic.org/docs/developers/device/http-api
|
||||
https://meshtastic.org/docs/developers/device/device-api
|
||||
https://github.com/meshtastic/Meshtastic-device/wiki/HTTP-REST-API-discussion
|
||||
https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/device-api.md
|
||||
|
||||
Example:
|
||||
http://10.10.30.198/api/v1/fromradio
|
||||
*/
|
||||
|
||||
// Get access to the parameters
|
||||
@@ -217,20 +233,24 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
/*
|
||||
For documentation, see:
|
||||
https://meshtastic.org/docs/developers/device/http-api
|
||||
https://meshtastic.org/docs/developers/device/device-api
|
||||
https://github.com/meshtastic/Meshtastic-device/wiki/HTTP-REST-API-discussion
|
||||
https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/device-api.md
|
||||
|
||||
Example:
|
||||
http://10.10.30.198/api/v1/toradio
|
||||
*/
|
||||
|
||||
// Status code is 200 OK by default.
|
||||
|
||||
res->setHeader("Content-Type", "application/x-protobuf");
|
||||
res->setHeader("Access-Control-Allow-Headers", "Content-Type");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "PUT, OPTIONS");
|
||||
res->setHeader("X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/Meshtastic-protobufs/master/mesh.proto");
|
||||
|
||||
|
||||
if (req->getMethod() == "OPTIONS") {
|
||||
res->setStatusCode(204); // Success with no content
|
||||
// res->print(""); @todo remove
|
||||
res->print("");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -244,8 +264,86 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
|
||||
DEBUG_MSG("--------------- webAPI handleAPIv1ToRadio\n");
|
||||
}
|
||||
|
||||
void handleFavicon(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
// Set Content-Type
|
||||
res->setHeader("Content-Type", "image/vnd.microsoft.icon");
|
||||
// Write data from header file
|
||||
res->write(FAVICON_DATA, FAVICON_LENGTH);
|
||||
}
|
||||
|
||||
void handleStaticPost(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
// Assume POST request. Contains submitted data.
|
||||
res->println("<html><head><title>File Edited</title><meta http-equiv=\"refresh\" content=\"1;url=/static\" "
|
||||
"/><head><body><h1>File Edited</h1>");
|
||||
|
||||
// The form is submitted with the x-www-form-urlencoded content type, so we need the
|
||||
// HTTPURLEncodedBodyParser to read the fields.
|
||||
// Note that the content of the file's content comes from a <textarea>, so we
|
||||
// can use the URL encoding here, since no file upload from an <input type="file"
|
||||
// is involved.
|
||||
HTTPURLEncodedBodyParser parser(req);
|
||||
|
||||
// The bodyparser will consume the request body. That means you can iterate over the
|
||||
// fields only ones. For that reason, we need to create variables for all fields that
|
||||
// we expect. So when parsing is done, you can process the field values from your
|
||||
// temporary variables.
|
||||
std::string filename;
|
||||
bool savedFile = false;
|
||||
|
||||
// Iterate over the fields from the request body by calling nextField(). This function
|
||||
// will update the field name and value of the body parsers. If the last field has been
|
||||
// reached, it will return false and the while loop stops.
|
||||
while (parser.nextField()) {
|
||||
// Get the field name, so that we can decide what the value is for
|
||||
std::string name = parser.getFieldName();
|
||||
|
||||
if (name == "filename") {
|
||||
// Read the filename from the field's value, add the /public prefix and store it in
|
||||
// the filename variable.
|
||||
char buf[512];
|
||||
size_t readLength = parser.read((byte *)buf, 512);
|
||||
// filename = std::string("/public/") + std::string(buf, readLength);
|
||||
filename = std::string(buf, readLength);
|
||||
|
||||
} else if (name == "content") {
|
||||
// Browsers must return the fields in the order that they are placed in
|
||||
// the HTML form, so if the broweser behaves correctly, this condition will
|
||||
// never be true. We include it for safety reasons.
|
||||
if (filename == "") {
|
||||
res->println("<p>Error: form contained content before filename.</p>");
|
||||
break;
|
||||
}
|
||||
|
||||
// With parser.read() and parser.endOfField(), we can stream the field content
|
||||
// into a buffer. That allows handling arbitrarily-sized field contents. Here,
|
||||
// we use it and write the file contents directly to the SPIFFS:
|
||||
size_t fieldLength = 0;
|
||||
File file = SPIFFS.open(filename.c_str(), "w");
|
||||
savedFile = true;
|
||||
while (!parser.endOfField()) {
|
||||
byte buf[512];
|
||||
size_t readLength = parser.read(buf, 512);
|
||||
file.write(buf, readLength);
|
||||
fieldLength += readLength;
|
||||
}
|
||||
file.close();
|
||||
res->printf("<p>Saved %d bytes to %s</p>", int(fieldLength), filename.c_str());
|
||||
|
||||
} else {
|
||||
res->printf("<p>Unexpected field %s</p>", name.c_str());
|
||||
}
|
||||
}
|
||||
if (!savedFile) {
|
||||
res->println("<p>No file to save...</p>");
|
||||
}
|
||||
res->println("</body></html>");
|
||||
}
|
||||
|
||||
void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
// jm
|
||||
|
||||
res->setHeader("Content-Type", "application/json");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
@@ -324,6 +422,206 @@ void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
To convert text to c strings:
|
||||
|
||||
https://tomeko.net/online_tools/cpp_text_escape.php?lang=en
|
||||
*/
|
||||
void handleRoot(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
res->setHeader("Content-Type", "text/html");
|
||||
|
||||
res->setHeader("Set-Cookie",
|
||||
"mt_session=" + httpsserver::intToString(random(1, 9999999)) + "; Expires=Wed, 20 Apr 2049 4:20:00 PST");
|
||||
|
||||
std::string cookie = req->getHeader("Cookie");
|
||||
// String cookieString = cookie.c_str();
|
||||
// uint8_t nameIndex = cookieString.indexOf("mt_session");
|
||||
// DEBUG_MSG(cookie.c_str());
|
||||
|
||||
std::string filename = "/static/index.html";
|
||||
std::string filenameGzip = "/static/index.html.gz";
|
||||
|
||||
if (!SPIFFS.exists(filename.c_str()) && !SPIFFS.exists(filenameGzip.c_str())) {
|
||||
// Send "404 Not Found" as response, as the file doesn't seem to exist
|
||||
res->setStatusCode(404);
|
||||
res->setStatusText("Not found");
|
||||
res->println("404 Not Found");
|
||||
res->printf("<p>File not found: %s</p>\n", filename.c_str());
|
||||
res->printf("<p></p>\n");
|
||||
res->printf("<p>You have gotten this error because the filesystem for the web server has not been loaded.</p>\n");
|
||||
res->printf("<p>Please review the 'Common Problems' section of the <a "
|
||||
"href=https://github.com/meshtastic/Meshtastic-device/wiki/"
|
||||
"How-to-use-the-Meshtastic-Web-Interface-over-WiFi>web interface</a> documentation.</p>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to open the file from SPIFFS
|
||||
File file;
|
||||
|
||||
if (SPIFFS.exists(filename.c_str())) {
|
||||
file = SPIFFS.open(filename.c_str());
|
||||
if (!file.available()) {
|
||||
DEBUG_MSG("File not available - %s\n", filename.c_str());
|
||||
}
|
||||
|
||||
} else if (SPIFFS.exists(filenameGzip.c_str())) {
|
||||
file = SPIFFS.open(filenameGzip.c_str());
|
||||
res->setHeader("Content-Encoding", "gzip");
|
||||
if (!file.available()) {
|
||||
DEBUG_MSG("File not available\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Read the file from SPIFFS and write it to the HTTP response body
|
||||
size_t length = 0;
|
||||
do {
|
||||
char buffer[256];
|
||||
length = file.read((uint8_t *)buffer, 256);
|
||||
std::string bufferString(buffer, length);
|
||||
res->write((uint8_t *)bufferString.c_str(), bufferString.size());
|
||||
} while (length > 0);
|
||||
}
|
||||
|
||||
void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
// Get access to the parameters
|
||||
ResourceParameters *params = req->getParams();
|
||||
std::string paramValDelete;
|
||||
std::string paramValEdit;
|
||||
|
||||
DEBUG_MSG("Static Browse - Disabling keep-alive\n");
|
||||
res->setHeader("Connection", "close");
|
||||
|
||||
// Set a default content type
|
||||
res->setHeader("Content-Type", "text/html");
|
||||
|
||||
if (params->getQueryParameter("delete", paramValDelete)) {
|
||||
std::string pathDelete = "/" + paramValDelete;
|
||||
if (SPIFFS.remove(pathDelete.c_str())) {
|
||||
Serial.println(pathDelete.c_str());
|
||||
res->println("<html><head><meta http-equiv=\"refresh\" content=\"1;url=/static\" /><title>File "
|
||||
"deleted!</title></head><body><h1>File deleted!</h1>");
|
||||
res->println("<meta http-equiv=\"refresh\" 1;url=/static\" />\n");
|
||||
res->println("</body></html>");
|
||||
|
||||
return;
|
||||
} else {
|
||||
Serial.println(pathDelete.c_str());
|
||||
res->println("<html><head><meta http-equiv=\"refresh\" content=\"1;url=/static\" /><title>Error deleteing "
|
||||
"file!</title></head><body><h1>Error deleteing file!</h1>");
|
||||
res->println("Error deleteing file!<br>");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->getQueryParameter("edit", paramValEdit)) {
|
||||
std::string pathEdit = "/" + paramValEdit;
|
||||
res->println("<html><head><title>Edit "
|
||||
"file</title></head><body><h1>Edit file - ");
|
||||
|
||||
res->println(pathEdit.c_str());
|
||||
|
||||
res->println("</h1>");
|
||||
res->println("<form method=post action=/static enctype=application/x-www-form-urlencoded>");
|
||||
res->printf("<input name=\"filename\" type=\"hidden\" value=\"%s\">", pathEdit.c_str());
|
||||
res->print("<textarea id=id name=content rows=20 cols=80>");
|
||||
|
||||
// Try to open the file from SPIFFS
|
||||
File file = SPIFFS.open(pathEdit.c_str());
|
||||
|
||||
if (file.available()) {
|
||||
// Read the file from SPIFFS and write it to the HTTP response body
|
||||
size_t length = 0;
|
||||
do {
|
||||
char buffer[256];
|
||||
length = file.read((uint8_t *)buffer, 256);
|
||||
std::string bufferString(buffer, length);
|
||||
|
||||
// Escape gt and lt
|
||||
replaceAll(bufferString, "<", "<");
|
||||
replaceAll(bufferString, ">", ">");
|
||||
|
||||
res->write((uint8_t *)bufferString.c_str(), bufferString.size());
|
||||
} while (length > 0);
|
||||
} else {
|
||||
res->println("Error: File not found");
|
||||
}
|
||||
|
||||
res->println("</textarea><br>");
|
||||
res->println("<input type=submit value=Submit>");
|
||||
res->println("</form>");
|
||||
res->println("</body></html>");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
res->println("<h2>Upload new file</h2>");
|
||||
res->println("<p>This form allows you to upload files. Keep your filenames small and files under 200k.</p>");
|
||||
res->println("<form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">");
|
||||
res->println("file: <input type=\"file\" name=\"file\"><br>");
|
||||
res->println("<input type=\"submit\" value=\"Upload\">");
|
||||
res->println("</form>");
|
||||
|
||||
res->println("<h2>All Files</h2>");
|
||||
|
||||
File root = SPIFFS.open("/");
|
||||
if (root.isDirectory()) {
|
||||
res->println("<script type=\"text/javascript\">function confirm_delete() {return confirm('Are you sure?');}</script>");
|
||||
|
||||
res->println("<table>");
|
||||
res->println("<tr>");
|
||||
res->println("<td>File");
|
||||
res->println("</td>");
|
||||
res->println("<td>Size");
|
||||
res->println("</td>");
|
||||
res->println("<td colspan=2>Actions");
|
||||
res->println("</td>");
|
||||
res->println("</tr>");
|
||||
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
String filePath = String(file.name());
|
||||
if (filePath.indexOf("/static") == 0) {
|
||||
res->println("<tr>");
|
||||
res->println("<td>");
|
||||
|
||||
if (String(file.name()).substring(1).endsWith(".gz")) {
|
||||
String modifiedFile = String(file.name()).substring(1);
|
||||
modifiedFile.remove((modifiedFile.length() - 3), 3);
|
||||
res->print("<a href=\"" + modifiedFile + "\">" + String(file.name()).substring(1) + "</a>");
|
||||
} else {
|
||||
res->print("<a href=\"" + String(file.name()).substring(1) + "\">" + String(file.name()).substring(1) +
|
||||
"</a>");
|
||||
}
|
||||
res->println("</td>");
|
||||
res->println("<td>");
|
||||
res->print(String(file.size()));
|
||||
res->println("</td>");
|
||||
res->println("<td>");
|
||||
res->print("<a href=\"/static?delete=" + String(file.name()).substring(1) +
|
||||
"\" onclick=\"return confirm_delete()\">Delete</a> ");
|
||||
res->println("</td>");
|
||||
res->println("<td>");
|
||||
if (!String(file.name()).substring(1).endsWith(".gz")) {
|
||||
res->print("<a href=\"/static?edit=" + String(file.name()).substring(1) + "\">Edit</a>");
|
||||
}
|
||||
res->println("</td>");
|
||||
res->println("</tr>");
|
||||
}
|
||||
|
||||
file = root.openNextFile();
|
||||
}
|
||||
res->println("</table>");
|
||||
|
||||
res->print("<br>");
|
||||
// res->print("Total : " + String(SPIFFS.totalBytes()) + " Bytes<br>");
|
||||
res->print("Used : " + String(SPIFFS.usedBytes()) + " Bytes<br>");
|
||||
res->print("Free : " + String(SPIFFS.totalBytes() - SPIFFS.usedBytes()) + " Bytes<br>");
|
||||
}
|
||||
}
|
||||
|
||||
void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
// Get access to the parameters
|
||||
@@ -336,33 +634,35 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
std::string filename = "/static/" + parameter1;
|
||||
std::string filenameGzip = "/static/" + parameter1 + ".gz";
|
||||
|
||||
if (!SPIFFS.exists(filename.c_str()) && !SPIFFS.exists(filenameGzip.c_str())) {
|
||||
// Send "404 Not Found" as response, as the file doesn't seem to exist
|
||||
res->setStatusCode(404);
|
||||
res->setStatusText("Not found");
|
||||
res->println("404 Not Found");
|
||||
res->printf("<p>File not found: %s</p>\n", filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to open the file from SPIFFS
|
||||
File file;
|
||||
|
||||
bool has_set_content_type = false;
|
||||
|
||||
if (SPIFFS.exists(filename.c_str())) {
|
||||
file = SPIFFS.open(filename.c_str());
|
||||
if (!file.available()) {
|
||||
DEBUG_MSG("File not available - %s\n", filename.c_str());
|
||||
}
|
||||
|
||||
} else if (SPIFFS.exists(filenameGzip.c_str())) {
|
||||
file = SPIFFS.open(filenameGzip.c_str());
|
||||
res->setHeader("Content-Encoding", "gzip");
|
||||
if (!file.available()) {
|
||||
DEBUG_MSG("File not available\n");
|
||||
}
|
||||
} else {
|
||||
has_set_content_type = true;
|
||||
filenameGzip = "/static/index.html.gz";
|
||||
file = SPIFFS.open(filenameGzip.c_str());
|
||||
res->setHeader("Content-Encoding", "gzip");
|
||||
res->setHeader("Content-Type", "text/html");
|
||||
}
|
||||
|
||||
res->setHeader("Content-Length", httpsserver::intToString(file.size()));
|
||||
|
||||
bool has_set_content_type = false;
|
||||
// Content-Type is guessed using the definition of the contentTypes-table defined above
|
||||
int cTypeIdx = 0;
|
||||
do {
|
||||
@@ -649,6 +949,30 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
res->println("}");
|
||||
}
|
||||
|
||||
// --------
|
||||
|
||||
void handle404(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
|
||||
// Discard request body, if we received any
|
||||
// We do this, as this is the default node and may also server POST/PUT requests
|
||||
req->discardRequestBody();
|
||||
|
||||
// Set the response status
|
||||
res->setStatusCode(404);
|
||||
res->setStatusText("Not Found");
|
||||
|
||||
// Set content type of the response
|
||||
res->setHeader("Content-Type", "text/html");
|
||||
|
||||
// Write a tiny HTTP page
|
||||
res->println("<!DOCTYPE html>");
|
||||
res->println("<html>");
|
||||
res->println("<head><title>Not Found</title></head>");
|
||||
res->println("<body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body>");
|
||||
res->println("</html>");
|
||||
}
|
||||
|
||||
/*
|
||||
This supports the Apple Captive Network Assistant (CNA) Portal
|
||||
*/
|
||||
|
||||
@@ -5,18 +5,25 @@ 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();
|
||||
|
||||
119
src/mesh/http/ContentStatic.h
Normal file
119
src/mesh/http/ContentStatic.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
/*
|
||||
This file contains static content.
|
||||
*/
|
||||
|
||||
// Length of the binary data
|
||||
const int FAVICON_LENGTH = 2238;
|
||||
|
||||
// Binary data for the favicon
|
||||
const byte FAVICON_DATA[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0xA8, 0x08, 0x00, 0x00, 0x16, 0x00, 0x00,
|
||||
0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x84,
|
||||
0xDC, 0x3D, 0x00, 0x84, 0xDC, 0x3C, 0x00, 0x85, 0xDC, 0x3F, 0x00, 0x86, 0xDD, 0x40, 0x00, 0x83, 0xDC, 0x3C, 0x00, 0x85, 0xDC,
|
||||
0x3E, 0x00, 0x82, 0xDC, 0x3A, 0x00, 0x8B, 0xDE, 0x49, 0x00, 0x84, 0xDB, 0x3E, 0x00, 0x82, 0xD9, 0x3C, 0x00, 0x89, 0xDD, 0x45,
|
||||
0x00, 0x83, 0xDB, 0x3C, 0x00, 0x83, 0xD8, 0x3D, 0x00, 0x81, 0xD8, 0x3A, 0x00, 0x8D, 0xE0, 0x49, 0x00, 0x88, 0xE4, 0x3F, 0x00,
|
||||
0x89, 0xE9, 0x3E, 0x00, 0x84, 0xD8, 0x40, 0x00, 0x85, 0xDF, 0x3C, 0x00, 0x8E, 0xF2, 0x40, 0x00, 0x8D, 0xF6, 0x3D, 0x00, 0x90,
|
||||
0xEA, 0x49, 0x00, 0x82, 0xD5, 0x3E, 0x00, 0x78, 0xC1, 0x3A, 0x00, 0x90, 0xE9, 0x4A, 0x00, 0x8E, 0xF5, 0x3D, 0x00, 0x84, 0xDD,
|
||||
0x3D, 0x00, 0x91, 0xF7, 0x43, 0x00, 0x87, 0xE5, 0x3D, 0x00, 0x6C, 0xA2, 0x38, 0x00, 0x53, 0x65, 0x31, 0x00, 0x41, 0x39, 0x2E,
|
||||
0x00, 0x3A, 0x27, 0x2B, 0x00, 0x34, 0x1A, 0x2A, 0x00, 0x41, 0x38, 0x2E, 0x00, 0x82, 0xD8, 0x3D, 0x00, 0x88, 0xE7, 0x3D, 0x00,
|
||||
0x8E, 0xF3, 0x41, 0x00, 0x69, 0x95, 0x39, 0x00, 0x3E, 0x33, 0x2C, 0x00, 0x31, 0x11, 0x29, 0x00, 0x2E, 0x0A, 0x29, 0x00, 0x2D,
|
||||
0x0B, 0x27, 0x00, 0x30, 0x10, 0x29, 0x00, 0x34, 0x18, 0x2A, 0x00, 0x3E, 0x31, 0x2C, 0x00, 0x68, 0x95, 0x39, 0x00, 0x88, 0xE7,
|
||||
0x3E, 0x00, 0x82, 0xD7, 0x3C, 0x00, 0x84, 0xDD, 0x3C, 0x00, 0x8B, 0xEE, 0x3E, 0x00, 0x85, 0xDF, 0x3D, 0x00, 0x47, 0x48, 0x2E,
|
||||
0x00, 0x30, 0x0F, 0x29, 0x00, 0x31, 0x13, 0x29, 0x00, 0x48, 0x4D, 0x2E, 0x00, 0x61, 0x7F, 0x39, 0x00, 0x6A, 0x9C, 0x38, 0x00,
|
||||
0x75, 0xB8, 0x39, 0x00, 0x85, 0xDE, 0x3D, 0x00, 0x8C, 0xEF, 0x3E, 0x00, 0x89, 0xDE, 0x44, 0x00, 0x80, 0xD1, 0x3C, 0x00, 0x3A,
|
||||
0x28, 0x2C, 0x00, 0x32, 0x16, 0x2A, 0x00, 0x33, 0x17, 0x2A, 0x00, 0x4B, 0x50, 0x30, 0x00, 0x76, 0xBA, 0x3A, 0x00, 0x8A, 0xEF,
|
||||
0x3C, 0x00, 0x9A, 0xFE, 0x4D, 0x00, 0x95, 0xFF, 0x43, 0x00, 0x93, 0xFF, 0x40, 0x00, 0x4B, 0x52, 0x30, 0x00, 0x7E, 0xCE, 0x3C,
|
||||
0x00, 0x87, 0xD9, 0x44, 0x00, 0x34, 0x1B, 0x2A, 0x00, 0x65, 0x90, 0x36, 0x00, 0x8E, 0xF6, 0x3D, 0x00, 0x8F, 0xF7, 0x40, 0x00,
|
||||
0x8B, 0xDD, 0x48, 0x00, 0x73, 0xB1, 0x3A, 0x00, 0x66, 0x95, 0x35, 0x00, 0x66, 0x93, 0x35, 0x00, 0x35, 0x1B, 0x2A, 0x00, 0x8D,
|
||||
0xE8, 0x45, 0x00, 0x82, 0xD9, 0x3B, 0x00, 0x72, 0xAA, 0x3C, 0x00, 0x95, 0xFD, 0x46, 0x00, 0x8D, 0xF0, 0x40, 0x00, 0x57, 0x70,
|
||||
0x32, 0x00, 0x3C, 0x2D, 0x2C, 0x00, 0x2F, 0x0D, 0x29, 0x00, 0x81, 0xD4, 0x3D, 0x00, 0x8D, 0xF1, 0x40, 0x00, 0x94, 0xFC, 0x46,
|
||||
0x00, 0x73, 0xAE, 0x3D, 0x00, 0x45, 0x44, 0x2D, 0x00, 0x94, 0xF5, 0x49, 0x00, 0x90, 0xF0, 0x45, 0x00, 0x73, 0xAF, 0x3B, 0x00,
|
||||
0x38, 0x21, 0x2C, 0x00, 0x30, 0x11, 0x29, 0x00, 0x2F, 0x0F, 0x28, 0x00, 0x72, 0xAC, 0x3B, 0x00, 0x6A, 0x93, 0x3D, 0x00, 0x2E,
|
||||
0x0D, 0x27, 0x00, 0x35, 0x1C, 0x2B, 0x00, 0x36, 0x20, 0x2A, 0x00, 0x5E, 0x77, 0x39, 0x00, 0x78, 0xBE, 0x3B, 0x00, 0x36, 0x21,
|
||||
0x2A, 0x00, 0x71, 0xAB, 0x3B, 0x00, 0x4C, 0x54, 0x30, 0x00, 0x3D, 0x31, 0x2B, 0x00, 0x82, 0xD6, 0x3D, 0x00, 0x79, 0xC5, 0x39,
|
||||
0x00, 0x9A, 0xFF, 0x4D, 0x00, 0x8A, 0xE8, 0x40, 0x00, 0x8A, 0xE7, 0x40, 0x00, 0x7A, 0xC6, 0x39, 0x00, 0x3D, 0x2E, 0x2C, 0x00,
|
||||
0x81, 0xD5, 0x3D, 0x00, 0x77, 0xBC, 0x3A, 0x00, 0x31, 0x12, 0x2A, 0x00, 0x69, 0x9B, 0x37, 0x00, 0x8E, 0xF3, 0x40, 0x00, 0x83,
|
||||
0xDC, 0x3B, 0x00, 0x8C, 0xF6, 0x3B, 0x00, 0x88, 0xD9, 0x45, 0x00, 0x86, 0xE1, 0x3D, 0x00, 0x85, 0xE0, 0x3D, 0x00, 0x7B, 0xC8,
|
||||
0x39, 0x00, 0x36, 0x1F, 0x29, 0x00, 0x55, 0x6B, 0x32, 0x00, 0x8A, 0xEE, 0x3C, 0x00, 0x48, 0x4B, 0x2E, 0x00, 0x51, 0x61, 0x31,
|
||||
0x00, 0x8C, 0xE0, 0x48, 0x00, 0x8B, 0xDE, 0x47, 0x00, 0x98, 0xEE, 0x55, 0x00, 0x5D, 0x79, 0x36, 0x00, 0x3A, 0x2A, 0x2B, 0x00,
|
||||
0x3A, 0x29, 0x2B, 0x00, 0x5C, 0x78, 0x36, 0x00, 0x60, 0x7C, 0x3A, 0x00, 0x3D, 0x30, 0x2C, 0x00, 0x99, 0xFD, 0x4C, 0x00, 0x66,
|
||||
0x8A, 0x3C, 0x00, 0x2D, 0x0C, 0x27, 0x00, 0x42, 0x3C, 0x2E, 0x00, 0x84, 0xDA, 0x3E, 0x00, 0x88, 0xE5, 0x3F, 0x00, 0x37, 0x22,
|
||||
0x2B, 0x00, 0x2E, 0x0B, 0x28, 0x00, 0x6A, 0x9B, 0x37, 0x00, 0x72, 0xAF, 0x3A, 0x00, 0x32, 0x15, 0x29, 0x00, 0x2A, 0x00, 0x28,
|
||||
0x00, 0x5B, 0x75, 0x35, 0x00, 0x89, 0xE8, 0x3D, 0x00, 0x78, 0xBF, 0x3A, 0x00, 0x73, 0xB4, 0x38, 0x00, 0x83, 0xDA, 0x3C, 0x00,
|
||||
0x84, 0xDE, 0x3C, 0x00, 0x85, 0xDD, 0x3E, 0x00, 0x86, 0xDE, 0x40, 0x00, 0x84, 0xDE, 0x3B, 0x00, 0x86, 0xE2, 0x3C, 0x00, 0x85,
|
||||
0xDD, 0x3F, 0x00, 0x87, 0xE2, 0x3F, 0x00, 0x87, 0xE1, 0x3E, 0x00, 0x85, 0xDE, 0x3E, 0x00, 0x89, 0xE2, 0x41, 0x00, 0x89, 0xE2,
|
||||
0x43, 0x00, 0x84, 0xDC, 0x3E, 0x00, 0x83, 0xD8, 0x3E, 0x00, 0x90, 0xF6, 0x41, 0x00, 0x2B, 0x04, 0x28, 0x00, 0x8C, 0xE3, 0x47,
|
||||
0x00, 0x8B, 0xDE, 0x48, 0x00, 0x8A, 0xDC, 0x47, 0x00, 0x8A, 0xDD, 0x47, 0x00, 0x8D, 0xDD, 0x4A, 0x00, 0x8A, 0xDE, 0x47, 0x00,
|
||||
0x8B, 0xDD, 0x49, 0x00, 0x8B, 0xE0, 0x46, 0x00, 0x9A, 0xF2, 0x55, 0x00, 0x59, 0x70, 0x35, 0x00, 0x8F, 0xDE, 0x4F, 0x00, 0x82,
|
||||
0xDC, 0x3B, 0x00, 0x82, 0xDB, 0x39, 0x00, 0x7F, 0xD7, 0x38, 0x00, 0x92, 0xF0, 0x48, 0x00, 0x33, 0x19, 0x29, 0x00, 0x87, 0xDD,
|
||||
0x42, 0x00, 0x87, 0xDD, 0x41, 0x00, 0x92, 0xEC, 0x4B, 0x00, 0x78, 0xBD, 0x3C, 0x00, 0x86, 0xDD, 0x3F, 0x00, 0x81, 0xD9, 0x39,
|
||||
0x00, 0x7B, 0xC4, 0x3C, 0x00, 0x34, 0x1A, 0x29, 0x00, 0x89, 0xDD, 0x44, 0x00, 0x86, 0xDC, 0x40, 0x00, 0x88, 0xDD, 0x44, 0x00,
|
||||
0x87, 0xDE, 0x41, 0x00, 0x99, 0xFA, 0x4F, 0x00, 0x7B, 0xC3, 0x3E, 0x00, 0x83, 0xD7, 0x3F, 0x00, 0x8B, 0xED, 0x3E, 0x00, 0x40,
|
||||
0x33, 0x2F, 0x00, 0x39, 0x27, 0x2B, 0x00, 0x81, 0xD7, 0x3B, 0x00, 0x3B, 0x2C, 0x2A, 0x00, 0x33, 0x18, 0x29, 0x00, 0x38, 0x22,
|
||||
0x2B, 0x00, 0x85, 0xDA, 0x40, 0x00, 0x89, 0xEA, 0x3D, 0x00, 0x6F, 0xA9, 0x38, 0x00, 0x70, 0xAB, 0x38, 0x00, 0x85, 0xDD, 0x3D,
|
||||
0x00, 0x88, 0xE1, 0x40, 0x00, 0x36, 0x1F, 0x2B, 0x00, 0x30, 0x13, 0x28, 0x00, 0x68, 0x9A, 0x36, 0x00, 0x90, 0xFB, 0x3F, 0x00,
|
||||
0x8A, 0xDD, 0x46, 0x00, 0x8D, 0xE9, 0x45, 0x00, 0x5A, 0x71, 0x36, 0x00, 0x27, 0x00, 0x24, 0x00, 0x73, 0x9F, 0x45, 0x00, 0x97,
|
||||
0xFE, 0x4A, 0x00, 0x86, 0xD8, 0x43, 0x00, 0x73, 0xA1, 0x45, 0x00, 0x8E, 0xDF, 0x4C, 0x00, 0x85, 0xDB, 0x40, 0x00, 0x72, 0xB5,
|
||||
0x37, 0x00, 0x95, 0xF4, 0x4B, 0x00, 0x73, 0xB6, 0x37, 0x00, 0x88, 0xE9, 0x3C, 0x00, 0x8A, 0xDB, 0x48, 0x00, 0x8C, 0xDE, 0x49,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0xAE, 0x06, 0xF1, 0x02, 0x04, 0x04, 0x02, 0xF1, 0x06, 0xAE, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01,
|
||||
0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0xAE, 0xC7, 0xF1, 0x02, 0x04,
|
||||
0x04, 0x02, 0xF1, 0xC7, 0xAE, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x02, 0x03, 0x0B, 0xAE, 0xEF, 0xF0, 0x02, 0x01, 0x01, 0x02, 0xB4, 0xEF, 0xAE, 0x0B, 0x03, 0x02, 0x01, 0x00,
|
||||
0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, 0xEB, 0xA7, 0xD1, 0xEC, 0xED, 0x96,
|
||||
0x04, 0x04, 0x96, 0xED, 0xEE, 0xD1, 0xA7, 0xEB, 0x05, 0x04, 0x01, 0x04, 0xCA, 0x04, 0x01, 0x01, 0x01, 0xCA, 0xCA, 0xCA, 0xCA,
|
||||
0xCA, 0xCA, 0xCA, 0xCC, 0xE2, 0x8A, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE8, 0xE7, 0xE9, 0xE5, 0xBB, 0xE3, 0x8A, 0xE2, 0xCC,
|
||||
0xCA, 0xCC, 0xEA, 0xCC, 0xCA, 0xCA, 0xCA, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x08, 0xDD, 0x55, 0xDE, 0x2C, 0xDF,
|
||||
0xE0, 0xE1, 0xE1, 0xE0, 0xDF, 0x2C, 0xDE, 0x55, 0xDD, 0x08, 0x04, 0x01, 0x04, 0xCA, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0xC6, 0xD8, 0xD9, 0xAB, 0x78, 0x6A, 0x28, 0xDA, 0xDB, 0x28, 0x6A, 0x5A, 0xDC, 0xD9, 0xD8, 0xC6,
|
||||
0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, 0x03, 0xD4, 0xD1, 0x31,
|
||||
0xD5, 0xD6, 0x98, 0xD7, 0xD6, 0xD5, 0x0B, 0x32, 0xD4, 0x03, 0x05, 0x04, 0x01, 0x04, 0xCA, 0x04, 0x01, 0x01, 0x01, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x05, 0xC3, 0xC2, 0xA4, 0xD0, 0xD1, 0xB3, 0xD2, 0xD3, 0xD3, 0xD2, 0x4F, 0x32, 0xD0, 0xA4, 0xC2,
|
||||
0xC3, 0x05, 0x02, 0x05, 0xB7, 0x05, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xCB, 0xC2, 0xCC, 0x02, 0xCD,
|
||||
0x79, 0xCE, 0xCF, 0xC1, 0xC1, 0xCF, 0xCE, 0x79, 0xCD, 0x02, 0xCC, 0xC2, 0xCB, 0x03, 0xCB, 0xB3, 0xCB, 0x03, 0x03, 0x03, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x7E, 0x05, 0xC6, 0x7E, 0x00, 0xC7, 0x15, 0xC8, 0xC9, 0xC9, 0xC8, 0x15, 0xC7, 0x00, 0x7E,
|
||||
0xC6, 0x05, 0x7E, 0x04, 0x7E, 0xCA, 0x7E, 0x04, 0x04, 0x04, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0x00, 0x03, 0xC3, 0x00,
|
||||
0x05, 0x55, 0xC4, 0xC5, 0xC1, 0xC1, 0xC5, 0xC4, 0x55, 0x05, 0x00, 0xC3, 0x03, 0x00, 0xAE, 0x00, 0x3D, 0x00, 0xAE, 0xAE, 0xAE,
|
||||
0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x7E, 0xBE, 0x00, 0x05, 0xBE, 0x7E, 0xBF, 0xC0, 0x5C, 0xC1, 0xC1, 0x5C, 0xC0, 0xBF, 0x7E,
|
||||
0xBE, 0x05, 0x00, 0xBE, 0x7E, 0xBE, 0xC2, 0x06, 0xBD, 0xBD, 0xBD, 0xB3, 0xB3, 0xB3, 0xB4, 0xB5, 0xB3, 0xB3, 0xB5, 0xB6, 0xB6,
|
||||
0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0x6B, 0x6B, 0xBB, 0xBA, 0xB9, 0xB8, 0xB7, 0xB6, 0xB6, 0xB5, 0xB3, 0xB5, 0xBC, 0xB4, 0xB3, 0xB3,
|
||||
0xB3, 0x02, 0x02, 0xA8, 0xA9, 0xAA, 0xA8, 0x02, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0x8F, 0xB1, 0x71, 0x2D, 0xB1, 0x9E, 0xB0,
|
||||
0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0x02, 0xA4, 0xB2, 0xAA, 0xA8, 0x02, 0x02, 0x04, 0x31, 0xA3, 0x04, 0x31, 0x82, 0x3B, 0xA3, 0xA4,
|
||||
0xA5, 0xA6, 0x82, 0xA7, 0x8E, 0x20, 0x78, 0x78, 0x20, 0x8E, 0xA7, 0x82, 0xA6, 0xA5, 0xA4, 0xA3, 0x3B, 0x82, 0x3D, 0x04, 0xA3,
|
||||
0x31, 0x04, 0x09, 0x9F, 0xA0, 0x21, 0x2C, 0xA1, 0x47, 0x52, 0x5B, 0x5A, 0xA2, 0x1C, 0x81, 0x8D, 0x8E, 0x91, 0x91, 0x8E, 0x8D,
|
||||
0x81, 0x1C, 0xA2, 0x5A, 0x5B, 0x52, 0x47, 0xA1, 0x2C, 0x21, 0xA0, 0x9F, 0x09, 0x96, 0x97, 0x16, 0x98, 0x99, 0x9A, 0x46, 0x9B,
|
||||
0x28, 0x9C, 0x6D, 0x76, 0x7D, 0x8C, 0x9D, 0x8E, 0x8E, 0x9D, 0x9E, 0x7D, 0x75, 0x6D, 0x9C, 0x65, 0x9B, 0x46, 0x39, 0x99, 0x98,
|
||||
0x16, 0x97, 0x96, 0x4F, 0x89, 0x15, 0x1F, 0x69, 0x38, 0x45, 0x8A, 0x78, 0x66, 0x6C, 0x74, 0x4A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x8B, 0x80, 0x45, 0x90, 0x66, 0x91, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x15, 0x89, 0x4F, 0x7E, 0x0D, 0x14, 0x1E, 0x29, 0x37, 0x44,
|
||||
0x14, 0x59, 0x65, 0x6B, 0x73, 0x7F, 0x80, 0x25, 0x81, 0x82, 0x25, 0x80, 0x7F, 0x83, 0x84, 0x65, 0x85, 0x4D, 0x86, 0x87, 0x29,
|
||||
0x88, 0x14, 0x0D, 0x7E, 0x05, 0x0C, 0x13, 0x1D, 0x28, 0x2C, 0x43, 0x4E, 0x72, 0x64, 0x53, 0x5A, 0x73, 0x74, 0x75, 0x1C, 0x1C,
|
||||
0x76, 0x74, 0x77, 0x78, 0x6A, 0x64, 0x79, 0x4E, 0x7A, 0x2C, 0x7B, 0x7C, 0x7D, 0x0C, 0x05, 0x04, 0x0B, 0x12, 0x1C, 0x27, 0x36,
|
||||
0x42, 0x4D, 0x5D, 0x63, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x1A, 0x1A, 0x6D, 0x6C, 0x6E, 0x53, 0x69, 0x6F, 0x5D, 0x19, 0x70, 0x36,
|
||||
0x71, 0x24, 0x12, 0x0B, 0x04, 0x03, 0x03, 0x11, 0x1B, 0x2E, 0x35, 0x41, 0x4C, 0x5E, 0x62, 0x63, 0x64, 0x65, 0x66, 0x2C, 0x5A,
|
||||
0x5A, 0x2C, 0x66, 0x65, 0x64, 0x67, 0x62, 0x5E, 0x52, 0x40, 0x65, 0x68, 0x1B, 0x11, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x25,
|
||||
0x34, 0x40, 0x4B, 0x56, 0x57, 0x58, 0x16, 0x59, 0x5A, 0x41, 0x5B, 0x5B, 0x41, 0x5A, 0x59, 0x5C, 0x5D, 0x5E, 0x5F, 0x21, 0x41,
|
||||
0x60, 0x61, 0x05, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x09, 0x24, 0x33, 0x3F, 0x2C, 0x4B, 0x4C, 0x4D, 0x4E, 0x14, 0x4F, 0x50,
|
||||
0x51, 0x51, 0x50, 0x4F, 0x14, 0x4E, 0x4D, 0x52, 0x53, 0x2C, 0x3F, 0x01, 0x54, 0x55, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1A,
|
||||
0x23, 0x32, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x46, 0x45, 0x44, 0x43, 0x48, 0x41, 0x40, 0x3F,
|
||||
0x49, 0x3C, 0x4A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x30, 0x32, 0x33, 0x34, 0x35, 0x36, 0x2C, 0x37, 0x38,
|
||||
0x39, 0x3A, 0x3A, 0x39, 0x38, 0x37, 0x2C, 0x36, 0x35, 0x34, 0x3B, 0x3C, 0x30, 0x3D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1A, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x2D, 0x2E, 0x13,
|
||||
0x2F, 0x30, 0x31, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x09, 0x02, 0x1B, 0x1C, 0x1D, 0x1E,
|
||||
0x1F, 0x20, 0x21, 0x21, 0x20, 0x22, 0x1E, 0x1D, 0x1C, 0x1B, 0x02, 0x09, 0x1A, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x17, 0x16, 0x18, 0x19, 0x13, 0x12, 0x11,
|
||||
0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x0B, 0x0C,
|
||||
0x0D, 0x0E, 0x0F, 0x10, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x03, 0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
|
||||
0x03, 0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "main.h"
|
||||
#include "mesh/http/WebServer.h"
|
||||
#include "NodeDB.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
@@ -78,7 +77,7 @@ static void taskCreateCert(void *parameter)
|
||||
{
|
||||
prefs.begin("MeshtasticHTTPS", false);
|
||||
|
||||
// Delete the saved certs (used in debugging)
|
||||
// Delete the saved certs
|
||||
if (0) {
|
||||
DEBUG_MSG("Deleting any saved SSL keys ...\n");
|
||||
// prefs.clear();
|
||||
@@ -167,16 +166,11 @@ void createSSLCert()
|
||||
NULL); /* Task handle. */
|
||||
|
||||
DEBUG_MSG("Waiting for SSL Cert to be generated.\n");
|
||||
int seconds = 0;
|
||||
while (!isCertReady) {
|
||||
DEBUG_MSG(".");
|
||||
delay(1000);
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
seconds++;
|
||||
if ((seconds == 3) && screen) {
|
||||
screen->setSSLFrames();
|
||||
}
|
||||
}
|
||||
DEBUG_MSG("SSL Cert Ready!\n");
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ static int32_t reconnectWiFi()
|
||||
if (*wifiName) {
|
||||
needReconnect = false;
|
||||
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point\n");
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point");
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
}
|
||||
|
||||
@@ -557,7 +557,7 @@ void setBluetoothEnable(bool on)
|
||||
|
||||
bluetoothOn = on;
|
||||
if (on) {
|
||||
if (!initWifi(isSoftAPForced())) // if we are using wifi, don't turn on bluetooth also
|
||||
if (!initWifi(0)) // if we are using wifi, don't turn on bluetooth also
|
||||
{
|
||||
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
|
||||
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
|
||||
|
||||
@@ -137,15 +137,10 @@ void AdminPlugin::handleSetOwner(const User &o)
|
||||
strcpy(owner.id, o.id);
|
||||
}
|
||||
if (owner.is_licensed != o.is_licensed) {
|
||||
changed = 1;
|
||||
changed = true;
|
||||
owner.is_licensed = o.is_licensed;
|
||||
}
|
||||
|
||||
if ((!changed || o.team) && (owner.team != o.team)) {
|
||||
changed = 1;
|
||||
owner.team = o.team;
|
||||
}
|
||||
|
||||
if (changed) // If nothing really changed, don't broadcast on the network or write to flash
|
||||
service.reloadOwner();
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ ExternalNotificationPlugin::ExternalNotificationPlugin()
|
||||
#endif
|
||||
}
|
||||
|
||||
ProcessMessage ExternalNotificationPlugin::handleReceived(const MeshPacket &mp)
|
||||
bool ExternalNotificationPlugin::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
@@ -176,5 +176,5 @@ ProcessMessage ExternalNotificationPlugin::handleReceived(const MeshPacket &mp)
|
||||
|
||||
#endif
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
return false; // Very important to never return TRUE here. TRUE means we handled the packet and we will stop letting other plugins see it
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ class ExternalNotificationPlugin : public SinglePortPlugin, private concurrency:
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp);
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
#include "plugins/RemoteHardwarePlugin.h"
|
||||
#include "plugins/ReplyPlugin.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
#include "plugins/SerialPlugin.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
#include "plugins/AdminPlugin.h"
|
||||
#ifndef NO_ESP32
|
||||
#include "plugins/esp32/SerialPlugin.h"
|
||||
#include "plugins/SerialPlugin.h"
|
||||
#include "plugins/esp32/EnvironmentalMeasurementPlugin.h"
|
||||
#include "plugins/esp32/RangeTestPlugin.h"
|
||||
#include "plugins/esp32/StoreForwardPlugin.h"
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "configuration.h"
|
||||
#include "PositionPlugin.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
|
||||
PositionPlugin *positionPlugin;
|
||||
|
||||
@@ -19,24 +18,6 @@ bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, Position *pptr
|
||||
{
|
||||
auto p = *pptr;
|
||||
|
||||
// If inbound message is a replay (or spoof!) of our own messages, we shouldn't process
|
||||
// (why use second-hand sources for our own data?)
|
||||
|
||||
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
|
||||
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
|
||||
if (nodeDB.getNodeNum() == getFrom(&mp)) {
|
||||
DEBUG_MSG("Incoming update from MYSELF\n");
|
||||
// DEBUG_MSG("Ignored an incoming update from MYSELF\n");
|
||||
// return false;
|
||||
}
|
||||
|
||||
// Log packet size and list of fields
|
||||
DEBUG_MSG("POSITION node=%08x l=%d %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", getFrom(&mp), mp.decoded.payload.size,
|
||||
p.latitude_i ? "LAT " : "", p.longitude_i ? "LON " : "", p.altitude ? "MSL " : "", p.altitude_hae ? "HAE " : "",
|
||||
p.alt_geoid_sep ? "GEO " : "", p.PDOP ? "PDOP " : "", p.HDOP ? "HDOP " : "", p.VDOP ? "VDOP " : "",
|
||||
p.sats_in_view ? "SIV " : "", p.fix_quality ? "FXQ " : "", p.fix_type ? "FXT " : "", p.pos_timestamp ? "PTS " : "",
|
||||
p.time ? "TIME " : "", p.battery_level ? "BAT " : "");
|
||||
|
||||
if (p.time) {
|
||||
struct timeval tv;
|
||||
uint32_t secs = p.time;
|
||||
@@ -57,44 +38,7 @@ MeshPacket *PositionPlugin::allocReply()
|
||||
NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position
|
||||
assert(node->has_position);
|
||||
|
||||
// configuration of POSITION packet
|
||||
// consider making this a function argument?
|
||||
uint32_t pos_flags = radioConfig.preferences.position_flags;
|
||||
|
||||
// Populate a Position struct with ONLY the requested fields
|
||||
Position p = Position_init_default; // Start with an empty structure
|
||||
|
||||
// lat/lon are unconditionally included - IF AVAILABLE!
|
||||
p.latitude_i = node->position.latitude_i;
|
||||
p.longitude_i = node->position.longitude_i;
|
||||
p.time = node->position.time;
|
||||
|
||||
if (pos_flags & PositionFlags_POS_BATTERY)
|
||||
p.battery_level = node->position.battery_level;
|
||||
|
||||
if (pos_flags & PositionFlags_POS_ALTITUDE) {
|
||||
if (pos_flags & PositionFlags_POS_ALT_MSL)
|
||||
p.altitude = node->position.altitude;
|
||||
else
|
||||
p.altitude_hae = node->position.altitude_hae;
|
||||
|
||||
if (pos_flags & PositionFlags_POS_GEO_SEP)
|
||||
p.alt_geoid_sep = node->position.alt_geoid_sep;
|
||||
}
|
||||
|
||||
if (pos_flags & PositionFlags_POS_DOP) {
|
||||
if (pos_flags & PositionFlags_POS_HVDOP) {
|
||||
p.HDOP = node->position.HDOP;
|
||||
p.VDOP = node->position.VDOP;
|
||||
} else
|
||||
p.PDOP = node->position.PDOP;
|
||||
}
|
||||
|
||||
if (pos_flags & PositionFlags_POS_SATINVIEW)
|
||||
p.sats_in_view = node->position.sats_in_view;
|
||||
|
||||
if (pos_flags & PositionFlags_POS_TIMESTAMP)
|
||||
p.pos_timestamp = node->position.pos_timestamp;
|
||||
Position p = node->position;
|
||||
|
||||
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
|
||||
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
|
||||
@@ -125,58 +69,18 @@ void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||
|
||||
int32_t PositionPlugin::runOnce()
|
||||
{
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
|
||||
// radioConfig.preferences.position_broadcast_smart = true;
|
||||
|
||||
// We limit our GPS broadcasts to a max rate
|
||||
uint32_t now = millis();
|
||||
if (lastGpsSend == 0 || now - lastGpsSend >= getPref_position_broadcast_secs() * 1000) {
|
||||
|
||||
lastGpsSend = now;
|
||||
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
|
||||
// If we changed channels, ask everyone else for their latest info
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
DEBUG_MSG("Sending pos@%x:6 to mesh (wantReplies=%d)\n", node->position.pos_timestamp, requestReplies);
|
||||
DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
} else if (radioConfig.preferences.position_broadcast_smart == true) {
|
||||
NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position
|
||||
|
||||
if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) {
|
||||
float distance = GeoCoord::latLongToMeter(lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7,
|
||||
node->position.latitude_i * 1e-7, node->position.longitude_i * 1e-7);
|
||||
|
||||
/* Please don't change these values. This accomodates for possible poor positioning
|
||||
in the event the GPS has a poor satelite lock.
|
||||
*/
|
||||
const uint8_t distanceTravel = 150;
|
||||
|
||||
/* Minimum time between position updates.
|
||||
Note: At an average walking speed of 3.5mph, it takes 90 seconds to travel 150 meters.
|
||||
*/
|
||||
const uint8_t timeTravel = 60;
|
||||
|
||||
// If the distance traveled since the last update is greater than 100 meters
|
||||
// and it's been at least 60 seconds since the last update
|
||||
if ((abs(distance) >= distanceTravel) &&
|
||||
(lastGpsSend == 0 || now - timeTravel >= getPref_position_broadcast_secs() * 1000)) {
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
DEBUG_MSG("Sending smart pos@%x:6 to mesh (wantReplies=%d)\n", node->position.pos_timestamp, requestReplies);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
|
||||
/* Update lastGpsSend to now. This means if the device is stationary, then
|
||||
getPref_position_broadcast_secs will still apply.
|
||||
*/
|
||||
lastGpsSend = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 5000; // to save power only wake for our callback occasionally
|
||||
|
||||
@@ -13,10 +13,6 @@ class PositionPlugin : public ProtobufPlugin<Position>, private concurrency::OST
|
||||
/// We limit our GPS broadcasts to a max rate
|
||||
uint32_t lastGpsSend = 0;
|
||||
|
||||
// Store the latest good lat / long
|
||||
uint32_t lastGpsLatitude = 0;
|
||||
uint32_t lastGpsLongitude = 0;
|
||||
|
||||
/// We force a rebroadcast if the radio settings change
|
||||
uint32_t currentGeneration = 0;
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
ProcessMessage SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
bool SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
@@ -207,5 +207,5 @@ ProcessMessage SerialPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
#endif
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
@@ -45,9 +45,9 @@ class SerialPluginRadio : public SinglePortPlugin
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp);
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern SerialPluginRadio *serialPluginRadio;
|
||||
extern SerialPluginRadio *serialPluginRadio;
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
TextMessagePlugin *textMessagePlugin;
|
||||
|
||||
ProcessMessage TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
||||
bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
DEBUG_MSG("Received text msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
|
||||
@@ -18,5 +18,5 @@ ProcessMessage TextMessagePlugin::handleReceived(const MeshPacket &mp)
|
||||
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
|
||||
notifyObservers(&mp);
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ class TextMessagePlugin : public SinglePortPlugin, public Observable<const MeshP
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp);
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern TextMessagePlugin *textMessagePlugin;
|
||||
@@ -1,23 +1,20 @@
|
||||
#include "EnvironmentalMeasurementPlugin.h"
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include <DHT.h>
|
||||
#include <DS18B20.h>
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
#include <OneWire.h>
|
||||
|
||||
#define DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
|
||||
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
|
||||
#define DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
|
||||
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 // Some sensors (the DHT11) have a minimum required duration between read attempts
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
|
||||
|
||||
#ifdef HAS_EINK
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16
|
||||
@@ -34,136 +31,123 @@
|
||||
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
|
||||
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
|
||||
|
||||
int32_t EnvironmentalMeasurementPlugin::runOnce()
|
||||
{
|
||||
|
||||
int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||
#ifndef NO_ESP32 // this only works on ESP32 devices
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
|
||||
/*radioConfig.preferences.environmental_measurement_plugin_measurement_enabled = 1;
|
||||
radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1;
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5;
|
||||
radioConfig.preferences.environmental_measurement_plugin_update_interval = 600;
|
||||
radioConfig.preferences.environmental_measurement_plugin_update_interval = 30;
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 60;
|
||||
radioConfig.preferences.environmental_measurement_plugin_display_farenheit = false;
|
||||
radioConfig.preferences.environmental_measurement_plugin_display_farenheit = true;
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_pin = 13;
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_type =
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType::
|
||||
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20;
|
||||
*/
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_type = RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType::RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11;*/
|
||||
|
||||
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled ||
|
||||
radioConfig.preferences.environmental_measurement_plugin_screen_enabled)) {
|
||||
if (! (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
|
||||
// If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do some setup
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled) {
|
||||
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled)
|
||||
{
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Initializing\n");
|
||||
// it's possible to have this plugin enabled, only for displaying values on the screen.
|
||||
// therefore, we should only enable the sensor loop if measurement is also enabled
|
||||
switch (radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
dht = new DHT(radioConfig.preferences.environmental_measurement_plugin_sensor_pin, DHT11);
|
||||
this->dht->begin();
|
||||
this->dht->read();
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened DHT11 on pin: %d\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
|
||||
return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20:
|
||||
oneWire = new OneWire(radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
|
||||
ds18b20 = new DS18B20(oneWire);
|
||||
this->ds18b20->begin();
|
||||
this->ds18b20->setResolution(12);
|
||||
this->ds18b20->requestTemperatures();
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened DS18B20 on pin: %d\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
|
||||
return (DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
default:
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin");
|
||||
return (INT32_MAX);
|
||||
switch(radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
dht = new DHT(radioConfig.preferences.environmental_measurement_plugin_sensor_pin,DHT11);
|
||||
this->dht->begin();
|
||||
this->dht->read();
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Opened DHT11 on pin: %d\n",radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin");
|
||||
return (INT32_MAX);
|
||||
break;
|
||||
}
|
||||
// begin reading measurements from the sensor
|
||||
// DHT have a max read-rate of 1HZ, so we should wait at least 1 second
|
||||
// after initializing the sensor before we try to read from it.
|
||||
// returning the interval here means that the next time OSThread
|
||||
// calls our plugin, we'll run the other branch of this if statement
|
||||
// and actually do a "sendOurEnvironmentalMeasurement()"
|
||||
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
return (INT32_MAX);
|
||||
} else {
|
||||
if (!radioConfig.preferences.environmental_measurement_plugin_measurement_enabled) {
|
||||
}
|
||||
else {
|
||||
if (!radioConfig.preferences.environmental_measurement_plugin_measurement_enabled)
|
||||
{
|
||||
// if we somehow got to a second run of this plugin with measurement disabled, then just wait forever
|
||||
// I can't imagine we'd ever get here though.
|
||||
return (INT32_MAX);
|
||||
}
|
||||
// this is not the first time OSThread library has called this function
|
||||
// so just do what we intend to do on the interval
|
||||
if (sensor_read_error_count > radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold) {
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_recovery_interval > 0) {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: TEMPORARILY DISABLED; The "
|
||||
"environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in "
|
||||
"%d seconds\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold,
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval);
|
||||
sensor_read_error_count = 0;
|
||||
return (radioConfig.preferences.environmental_measurement_plugin_recovery_interval * 1000);
|
||||
if(sensor_read_error_count > radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold)
|
||||
{
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_recovery_interval > 0 ) {
|
||||
DEBUG_MSG(
|
||||
"EnvironmentalMeasurement: TEMPORARILY DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in %d seconds\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold,
|
||||
radioConfig.preferences.environmental_measurement_plugin_recovery_interval);
|
||||
sensor_read_error_count = 0;
|
||||
return(radioConfig.preferences.environmental_measurement_plugin_recovery_interval*1000);
|
||||
}
|
||||
DEBUG_MSG("EnvironmentalMeasurement: DISABLED; The environmental_measurement_plugin_read_error_count_threshold has "
|
||||
"been exceed: %d. Reads will not be retried until after device reset\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold);
|
||||
return (INT32_MAX);
|
||||
DEBUG_MSG(
|
||||
"EnvironmentalMeasurement: DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Reads will not be retried until after device reset\n",
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold);
|
||||
return(INT32_MAX);
|
||||
|
||||
} else if (sensor_read_error_count > 0) {
|
||||
DEBUG_MSG("EnvironmentalMeasurement: There have been %d sensor read failures. Will retry %d more times\n",
|
||||
sensor_read_error_count, sensor_read_error_count, sensor_read_error_count,
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold -
|
||||
sensor_read_error_count);
|
||||
|
||||
}
|
||||
if (!sendOurEnvironmentalMeasurement()) {
|
||||
// if we failed to read the sensor, then try again
|
||||
else if (sensor_read_error_count > 0){
|
||||
DEBUG_MSG("EnvironmentalMeasurement: There have been %d sensor read failures. Will retry %d more times\n",
|
||||
sensor_read_error_count,
|
||||
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold-sensor_read_error_count);
|
||||
}
|
||||
if (!sendOurEnvironmentalMeasurement() ){
|
||||
// if we failed to read the sensor, then try again
|
||||
// as soon as we can according to the maximum polling frequency
|
||||
// return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
|
||||
switch (radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20:
|
||||
return (DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
default:
|
||||
return (DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
}
|
||||
// The return of runOnce is an int32 representing the desired number of
|
||||
// miliseconds until the function should be called again by the
|
||||
// The return of runOnce is an int32 representing the desired number of
|
||||
// miliseconds until the function should be called again by the
|
||||
// OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds
|
||||
return (radioConfig.preferences.environmental_measurement_plugin_update_interval * 1000);
|
||||
return(radioConfig.preferences.environmental_measurement_plugin_update_interval * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPlugin::wantUIFrame()
|
||||
{
|
||||
bool EnvironmentalMeasurementPlugin::wantUIFrame() {
|
||||
return radioConfig.preferences.environmental_measurement_plugin_screen_enabled;
|
||||
}
|
||||
|
||||
String GetSenderName(const MeshPacket &mp)
|
||||
{
|
||||
String GetSenderName(const MeshPacket &mp) {
|
||||
String sender;
|
||||
|
||||
auto node = nodeDB.getNode(getFrom(&mp));
|
||||
if (node) {
|
||||
if (node){
|
||||
sender = node->user.short_name;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sender = "UNK";
|
||||
}
|
||||
return sender;
|
||||
}
|
||||
|
||||
uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp)
|
||||
{
|
||||
uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp) {
|
||||
uint32_t now = getTime();
|
||||
|
||||
uint32_t last_seen = mp->rx_time;
|
||||
@@ -172,13 +156,15 @@ uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp)
|
||||
delta = 0;
|
||||
|
||||
return delta;
|
||||
|
||||
}
|
||||
|
||||
float EnvironmentalMeasurementPlugin::CelsiusToFarenheit(float c)
|
||||
{
|
||||
return (c * 9) / 5 + 32;
|
||||
|
||||
float EnvironmentalMeasurementPlugin::CelsiusToFarenheit(float c) {
|
||||
return (c*9)/5 + 32;
|
||||
}
|
||||
|
||||
|
||||
void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
@@ -187,16 +173,21 @@ void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplay
|
||||
if (lastMeasurementPacket == nullptr) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement");
|
||||
//DEBUG_MSG("EnvironmentalMeasurement: No previous measurement; not drawing frame\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EnvironmentalMeasurement lastMeasurement;
|
||||
|
||||
|
||||
|
||||
uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket);
|
||||
String lastSender = GetSenderName(*lastMeasurementPacket);
|
||||
|
||||
auto &p = lastMeasurementPacket->decoded;
|
||||
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, EnvironmentalMeasurement_fields, &lastMeasurement)) {
|
||||
if (!pb_decode_from_bytes(p.payload.bytes,
|
||||
p.payload.size,
|
||||
EnvironmentalMeasurement_fields,
|
||||
&lastMeasurement)) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
|
||||
DEBUG_MSG("EnvironmentalMeasurement: unable to decode last packet");
|
||||
@@ -204,23 +195,20 @@ void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplay
|
||||
}
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
String last_temp = String(lastMeasurement.temperature, 0) + "°C";
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_display_farenheit) {
|
||||
last_temp = String(CelsiusToFarenheit(lastMeasurement.temperature), 0) + "°F";
|
||||
;
|
||||
String last_temp = String(lastMeasurement.temperature,0) +"°C";
|
||||
if (radioConfig.preferences.environmental_measurement_plugin_display_farenheit){
|
||||
last_temp = String(CelsiusToFarenheit(lastMeasurement.temperature),0) +"°F";;
|
||||
}
|
||||
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM),
|
||||
lastSender + ": " + last_temp + "/" + String(lastMeasurement.relative_humidity, 0) + "%(" +
|
||||
String(agoSecs) + "s)");
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": "+last_temp +"/"+ String(lastMeasurement.relative_humidity,0) + "%("+String(agoSecs)+"s)");
|
||||
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, EnvironmentalMeasurement *p)
|
||||
{
|
||||
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled ||
|
||||
radioConfig.preferences.environmental_measurement_plugin_screen_enabled)) {
|
||||
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
|
||||
return false;
|
||||
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
|
||||
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
|
||||
return false;
|
||||
}
|
||||
|
||||
String sender = GetSenderName(mp);
|
||||
@@ -242,32 +230,13 @@ bool EnvironmentalMeasurementPlugin::sendOurEnvironmentalMeasurement(NodeNum des
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Read data\n");
|
||||
|
||||
switch (radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
|
||||
if (!this->dht->read(true)) {
|
||||
sensor_read_error_count++;
|
||||
DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n");
|
||||
return false;
|
||||
}
|
||||
m.relative_humidity = this->dht->readHumidity();
|
||||
m.temperature = this->dht->readTemperature();
|
||||
break;
|
||||
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DS18B20:
|
||||
if (this->ds18b20->isConversionComplete()) {
|
||||
m.temperature = this->ds18b20->getTempC();
|
||||
m.relative_humidity = 0; // This sensor is temperature only
|
||||
this->ds18b20->requestTemperatures();
|
||||
break;
|
||||
} else {
|
||||
sensor_read_error_count++;
|
||||
DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n");
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin");
|
||||
if (!this->dht->read(true)){
|
||||
sensor_read_error_count++;
|
||||
DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n");
|
||||
return false;
|
||||
}
|
||||
m.relative_humidity = this->dht->readHumidity();
|
||||
m.temperature = this->dht->readTemperature();
|
||||
|
||||
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity);
|
||||
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature);
|
||||
@@ -281,3 +250,4 @@ bool EnvironmentalMeasurementPlugin::sendOurEnvironmentalMeasurement(NodeNum des
|
||||
service.sendToMesh(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
#pragma once
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include "ProtobufPlugin.h"
|
||||
#include <DHT.h>
|
||||
#include <DS18B20.h>
|
||||
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
#include <OneWire.h>
|
||||
#include <DHT.h>
|
||||
|
||||
class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public ProtobufPlugin<EnvironmentalMeasurement>
|
||||
{
|
||||
public:
|
||||
EnvironmentalMeasurementPlugin()
|
||||
: concurrency::OSThread("EnvironmentalMeasurementPlugin"),
|
||||
ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg)
|
||||
{
|
||||
lastMeasurementPacket = nullptr;
|
||||
EnvironmentalMeasurementPlugin(): concurrency::OSThread("EnvironmentalMeasurementPlugin"), ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) {
|
||||
lastMeasurementPacket = nullptr;
|
||||
}
|
||||
virtual bool wantUIFrame();
|
||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
@@ -29,13 +24,11 @@ class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public Pro
|
||||
* Send our EnvironmentalMeasurement into the mesh
|
||||
*/
|
||||
bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
|
||||
private:
|
||||
float CelsiusToFarenheit(float c);
|
||||
bool firstTime = 1;
|
||||
DHT *dht;
|
||||
OneWire *oneWire;
|
||||
DS18B20 *ds18b20;
|
||||
DHT* dht;
|
||||
const MeshPacket *lastMeasurementPacket;
|
||||
uint32_t sensor_read_error_count = 0;
|
||||
};
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include <Arduino.h>
|
||||
#include <SPIFFS.h>
|
||||
//#include <assert.h>
|
||||
@@ -124,7 +123,7 @@ void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
||||
}
|
||||
|
||||
ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
@@ -151,7 +150,6 @@ ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
appendFile(mp);
|
||||
}
|
||||
|
||||
/*
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
||||
DEBUG_MSG("p.payload.size %d\n", p.payload.size);
|
||||
@@ -175,7 +173,6 @@ ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
*/
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -184,7 +181,28 @@ ProcessMessage RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
#endif
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
/// Ported from my old java code, returns distance in meters along the globe
|
||||
/// surface (by magic?)
|
||||
float RangeTestPluginRadio::latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
||||
{
|
||||
double pk = (180 / 3.14169);
|
||||
double a1 = lat_a / pk;
|
||||
double a2 = lng_a / pk;
|
||||
double b1 = lat_b / pk;
|
||||
double b2 = lng_b / pk;
|
||||
double cos_b1 = cos(b1);
|
||||
double cos_a1 = cos(a1);
|
||||
double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2);
|
||||
double t2 = cos_a1 * sin(a2) * cos_b1 * sin(b2);
|
||||
double t3 = sin(a1) * sin(b1);
|
||||
double tt = acos(t1 + t2 + t3);
|
||||
if (isnan(tt))
|
||||
tt = 0.0; // Must have been the same point?
|
||||
|
||||
return (float)(6366000 * tt);
|
||||
}
|
||||
|
||||
bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
@@ -239,7 +257,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
|
||||
// Print the CSV header
|
||||
if (fileToWrite.println(
|
||||
"time,from,sender name,sender lat,sender long,rx lat,rx long,rx elevation,rx snr,distance,payload")) {
|
||||
"time,from,sender name,sender lat,sender long,rx lat,rx long,rx snr,rx elevation,distance,payload")) {
|
||||
DEBUG_MSG("File was written\n");
|
||||
} else {
|
||||
DEBUG_MSG("File write failed\n");
|
||||
@@ -285,7 +303,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
fileToAppend.printf("%f,", mp.rx_snr); // RX SNR
|
||||
|
||||
if (n->position.latitude_i && n->position.longitude_i && gpsStatus->getLatitude() && gpsStatus->getLongitude()) {
|
||||
float distance = GeoCoord::latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7,
|
||||
float distance = latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7,
|
||||
gpsStatus->getLatitude() * 1e-7, gpsStatus->getLongitude() * 1e-7);
|
||||
fileToAppend.printf("%f,", distance); // Distance in meters
|
||||
} else {
|
||||
|
||||
@@ -50,9 +50,9 @@ class RangeTestPluginRadio : public SinglePortPlugin
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp);
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/generated/storeforward.pb.h"
|
||||
#include "plugins/PluginDev.h"
|
||||
#include <Arduino.h>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
|
||||
#define STOREFORWARD_MAX_PACKETS 0
|
||||
#define STOREFORWARD_SEND_HISTORY_PERIOD 10 * 60
|
||||
#define STOREFORWARD_SEND_HISTORY_MAX 0
|
||||
|
||||
StoreForwardPlugin *storeForwardPlugin;
|
||||
|
||||
int32_t StoreForwardPlugin::runOnce()
|
||||
@@ -21,31 +23,22 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
if (radioConfig.preferences.is_router) {
|
||||
|
||||
if (this->busy) {
|
||||
// Send out the message queue.
|
||||
|
||||
// DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
|
||||
storeForwardPlugin->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
|
||||
|
||||
if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) {
|
||||
strcpy(this->routerMessage, "** S&F - Done");
|
||||
storeForwardPlugin->sendMessage(this->busyTo, this->routerMessage);
|
||||
// DEBUG_MSG("--- --- --- In busy loop - Done \n");
|
||||
this->packetHistoryTXQueue_index = 0;
|
||||
this->busy = false;
|
||||
} else {
|
||||
this->packetHistoryTXQueue_index++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Dynamicly adjust the time this returns in the loop based on the size of the packets being actually
|
||||
// transmitted.
|
||||
return (this->packetTimeMax);
|
||||
// Maybe some cleanup functions?
|
||||
this->historyReport();
|
||||
return (60 * 1000);
|
||||
} else {
|
||||
DEBUG_MSG("Store & Forward Plugin - Disabled (is_router = false)\n");
|
||||
/*
|
||||
* If the plugin is turned on and is_router is not enabled, then we'll send a heartbeat every
|
||||
* few minutes.
|
||||
*
|
||||
* This behavior is expected to change. It's only here until we come up with something better.
|
||||
*/
|
||||
|
||||
return (INT32_MAX);
|
||||
DEBUG_MSG("Store & Forward Plugin - Sending heartbeat\n");
|
||||
|
||||
storeForwardPlugin->sendPayload();
|
||||
|
||||
return (4 * 60 * 1000);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -58,9 +51,6 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
Create our data structure in the PSRAM.
|
||||
*/
|
||||
void StoreForwardPlugin::populatePSRAM()
|
||||
{
|
||||
/*
|
||||
@@ -68,8 +58,6 @@ void StoreForwardPlugin::populatePSRAM()
|
||||
https://learn.upesy.com/en/programmation/psram.html#psram-tab
|
||||
*/
|
||||
|
||||
uint32_t store_forward_plugin_replay_max_records = 250;
|
||||
|
||||
DEBUG_MSG("Before PSRAM initilization:\n");
|
||||
|
||||
DEBUG_MSG(" Total heap: %d\n", ESP.getHeapSize());
|
||||
@@ -77,14 +65,12 @@ void StoreForwardPlugin::populatePSRAM()
|
||||
DEBUG_MSG(" Total PSRAM: %d\n", ESP.getPsramSize());
|
||||
DEBUG_MSG(" Free PSRAM: %d\n", ESP.getFreePsram());
|
||||
|
||||
// Use a maximum of 2/3 the available PSRAM unless otherwise specified.
|
||||
// Use a maximum of half the available PSRAM unless otherwise specified.
|
||||
uint32_t numberOfPackets =
|
||||
(radioConfig.preferences.store_forward_plugin_records ? radioConfig.preferences.store_forward_plugin_records
|
||||
: (((ESP.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct)));
|
||||
STOREFORWARD_MAX_PACKETS ? STOREFORWARD_MAX_PACKETS : ((ESP.getPsramSize() / 2) / sizeof(PacketHistoryStruct));
|
||||
|
||||
// this->packetHistory = (PacketHistoryStruct *)ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct));
|
||||
this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct)));
|
||||
this->packetHistoryTXQueue =
|
||||
static_cast<PacketHistoryStruct *>(ps_calloc(store_forward_plugin_replay_max_records, sizeof(PacketHistoryStruct)));
|
||||
DEBUG_MSG("After PSRAM initilization:\n");
|
||||
|
||||
DEBUG_MSG(" Total heap: %d\n", ESP.getHeapSize());
|
||||
@@ -92,13 +78,34 @@ void StoreForwardPlugin::populatePSRAM()
|
||||
DEBUG_MSG(" Total PSRAM: %d\n", ESP.getPsramSize());
|
||||
DEBUG_MSG(" Free PSRAM: %d\n", ESP.getFreePsram());
|
||||
DEBUG_MSG("Store and Forward Stats:\n");
|
||||
DEBUG_MSG(" numberOfPackets for packetHistory - %u\n", numberOfPackets);
|
||||
DEBUG_MSG(" numberOfPackets - %u\n", numberOfPackets);
|
||||
}
|
||||
|
||||
// We saw a node.
|
||||
void StoreForwardPlugin::sawNode(uint32_t whoWeSaw, uint32_t sawSecAgo)
|
||||
{
|
||||
if (radioConfig.preferences.is_router) {
|
||||
|
||||
// If node has been away for more than 10 minutes, send the node the last 10 minutes of
|
||||
// messages
|
||||
if (sawSecAgo > STOREFORWARD_SEND_HISTORY_PERIOD) {
|
||||
// Node has been away for a while.
|
||||
storeForwardPlugin->historySend(STOREFORWARD_SEND_HISTORY_PERIOD, whoWeSaw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::historyReport()
|
||||
{
|
||||
DEBUG_MSG("Iterating through the message history...\n");
|
||||
DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent);
|
||||
uint32_t startTimer = millis();
|
||||
for (int i = 0; i < this->packetHistoryCurrent; i++) {
|
||||
if (this->packetHistory[i].time) {
|
||||
// DEBUG_MSG("... time-%u to-0x%08x\n", this->packetHistory[i].time, this->packetHistory[i].to & 0xffffffff);
|
||||
}
|
||||
}
|
||||
DEBUG_MSG("StoreForwardPlugin::historyReport runtime - %u ms\n", millis() - startTimer);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,75 +113,31 @@ void StoreForwardPlugin::historyReport()
|
||||
*/
|
||||
void StoreForwardPlugin::historySend(uint32_t msAgo, uint32_t to)
|
||||
{
|
||||
|
||||
uint32_t packetsSent = 0;
|
||||
|
||||
uint32_t queueSize = storeForwardPlugin->historyQueueCreate(msAgo, to);
|
||||
|
||||
if (queueSize) {
|
||||
snprintf(this->routerMessage, 80, "** S&F - Sending %d message(s)", queueSize);
|
||||
storeForwardPlugin->sendMessage(to, this->routerMessage);
|
||||
|
||||
this->busy = true; // runOnce() will pickup the next steps once busy = true.
|
||||
this->busyTo = to;
|
||||
|
||||
} else {
|
||||
strcpy(this->routerMessage, "** S&F - No history to send");
|
||||
storeForwardPlugin->sendMessage(to, this->routerMessage);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t StoreForwardPlugin::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
{
|
||||
|
||||
// uint32_t packetHistoryTXQueueIndex = 0;
|
||||
|
||||
this->packetHistoryTXQueue_size = 0;
|
||||
// Send "Welcome back"
|
||||
this->sendPayloadWelcome(to, false);
|
||||
|
||||
for (int i = 0; i < this->packetHistoryCurrent; i++) {
|
||||
/*
|
||||
DEBUG_MSG("SF historyQueueCreate\n");
|
||||
DEBUG_MSG("SF historyQueueCreate - time %d\n", this->packetHistory[i].time);
|
||||
DEBUG_MSG("SF historyQueueCreate - millis %d\n", millis());
|
||||
DEBUG_MSG("SF historyQueueCreate - math %d\n", (millis() - msAgo));
|
||||
*/
|
||||
if (this->packetHistory[i].time && (this->packetHistory[i].time < (millis() - msAgo))) {
|
||||
DEBUG_MSG("SF historyQueueCreate - Time matches - ok\n");
|
||||
/*
|
||||
Copy the messages that were received by the router in the last msAgo
|
||||
to the packetHistoryTXQueue structure.
|
||||
|
||||
TODO: The condition (this->packetHistory[i].to & 0xffffffff) == to) is not tested since
|
||||
I don't have an easy way to target a specific user. Will need to do this soon.
|
||||
*/
|
||||
if ((this->packetHistory[i].to & 0xffffffff) == 0xffffffff || ((this->packetHistory[i].to & 0xffffffff) == to)) {
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time;
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].to = this->packetHistory[i].to;
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from;
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload_size = this->packetHistory[i].payload_size;
|
||||
memcpy(this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload, this->packetHistory[i].payload,
|
||||
Constants_DATA_PAYLOAD_LEN);
|
||||
this->packetHistoryTXQueue_size++;
|
||||
|
||||
DEBUG_MSG("PacketHistoryStruct time=%d\n", this->packetHistory[i].time);
|
||||
DEBUG_MSG("PacketHistoryStruct msg=%.*s\n", this->packetHistory[i].payload);
|
||||
// DEBUG_MSG("PacketHistoryStruct msg=%.*s\n", this->packetHistoryTXQueue[packetHistoryTXQueueIndex].payload);
|
||||
}
|
||||
if (this->packetHistory[i].time) {
|
||||
// DEBUG_MSG("... time-%u to-0x%08x\n", this->packetHistory[i].time, this->packetHistory[i].to & 0xffffffff);
|
||||
}
|
||||
}
|
||||
return this->packetHistoryTXQueue_size;
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::historyAdd(const MeshPacket &mp)
|
||||
void StoreForwardPlugin::historyAdd(const MeshPacket *mp)
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
auto &p = mp;
|
||||
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
assert(numbytes <= MAX_RHPACKETLEN);
|
||||
|
||||
DEBUG_MSG("MP numbytes %u\n", numbytes);
|
||||
|
||||
// destination, source, bytes
|
||||
// memcpy(p->encrypted.bytes, bytes, numbytes);
|
||||
memcpy(this->packetHistory[this->packetHistoryCurrent].bytes, bytes, MAX_RHPACKETLEN);
|
||||
this->packetHistory[this->packetHistoryCurrent].time = millis();
|
||||
this->packetHistory[this->packetHistoryCurrent].to = mp.to;
|
||||
this->packetHistory[this->packetHistoryCurrent].from = mp.from;
|
||||
this->packetHistory[this->packetHistoryCurrent].payload_size = p.payload.size;
|
||||
memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, Constants_DATA_PAYLOAD_LEN);
|
||||
|
||||
this->packetHistory[this->packetHistoryCurrent].to = mp->to;
|
||||
this->packetHistoryCurrent++;
|
||||
}
|
||||
|
||||
@@ -184,87 +147,64 @@ MeshPacket *StoreForwardPlugin::allocReply()
|
||||
return reply;
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::sendPayload(NodeNum dest, uint32_t packetHistory_index)
|
||||
void StoreForwardPlugin::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
DEBUG_MSG("Sending S&F Payload\n");
|
||||
MeshPacket *p = allocReply();
|
||||
|
||||
p->to = dest;
|
||||
p->from = this->packetHistoryTXQueue[packetHistory_index].from;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
// Let's assume that if the router received the S&F request that the client is in range.
|
||||
// TODO: Make this configurable.
|
||||
p->want_ack = false;
|
||||
p->want_ack = true;
|
||||
|
||||
p->decoded.payload.size =
|
||||
this->packetHistoryTXQueue[packetHistory_index].payload_size; // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, this->packetHistoryTXQueue[packetHistory_index].payload,
|
||||
this->packetHistoryTXQueue[packetHistory_index].payload_size);
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "1");
|
||||
|
||||
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, "1", 1);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::sendMessage(NodeNum dest, char *str)
|
||||
void StoreForwardPlugin::sendPayloadWelcome(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
DEBUG_MSG("*********************************\n");
|
||||
DEBUG_MSG("*********************************\n");
|
||||
DEBUG_MSG("*********************************\n");
|
||||
DEBUG_MSG("Sending S&F Welcome Message\n");
|
||||
DEBUG_MSG("*********************************\n");
|
||||
DEBUG_MSG("*********************************\n");
|
||||
DEBUG_MSG("*********************************\n");
|
||||
MeshPacket *p = allocReply();
|
||||
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
// Let's assume that if the router received the S&F request that the client is in range.
|
||||
// TODO: Make this configurable.
|
||||
p->want_ack = false;
|
||||
p->want_ack = true;
|
||||
|
||||
p->decoded.payload.size = strlen(str); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, str, strlen(str));
|
||||
p->decoded.portnum = PortNum_TEXT_MESSAGE_APP;
|
||||
|
||||
static char heartbeatString[80];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "Welcome back to the mesh. We have not seen you in x minutes!");
|
||||
|
||||
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, heartbeatString, p->decoded.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
|
||||
// HardwareMessage_init_default
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
bool StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
DEBUG_MSG("--- S&F Received something\n");
|
||||
|
||||
/*
|
||||
StoreAndForwardMessage sfm = StoreAndForwardMessage_init_default;
|
||||
|
||||
switch (sfm.rr) {
|
||||
}
|
||||
*/
|
||||
auto &p = mp.decoded;
|
||||
|
||||
// The router node should not be sending messages as a client.
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
|
||||
printPacket("----- PACKET FROM RADIO -----", &mp);
|
||||
// uint32_t sawTime = storeForwardPlugin->sawNode(getFrom(&mp) & 0xffffffff);
|
||||
// DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from & 0xffffffff, (millis() - sawTime) / 1000);
|
||||
DEBUG_MSG(" -------------- ");
|
||||
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n");
|
||||
|
||||
if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 0x00)) {
|
||||
DEBUG_MSG("--- --- --- Request to send\n");
|
||||
|
||||
// Send the last 60 minutes of messages.
|
||||
if (this->busy) {
|
||||
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
|
||||
storeForwardPlugin->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
} else {
|
||||
storeForwardPlugin->historySend(1000 * 60, getFrom(&mp));
|
||||
}
|
||||
} else if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 'm') &&
|
||||
(p.payload.bytes[3] == 0x00)) {
|
||||
strcpy(this->routerMessage, "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"01234567890123456789012345678901234567890123456789012345678901234567890123456");
|
||||
storeForwardPlugin->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
|
||||
} else {
|
||||
storeForwardPlugin->historyAdd(mp);
|
||||
}
|
||||
|
||||
} else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) {
|
||||
storeForwardPlugin->historyAdd(&mp);
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum);
|
||||
@@ -277,86 +217,25 @@ ProcessMessage StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
|
||||
#endif
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlugin::handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p)
|
||||
{
|
||||
if (!radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
//auto sfp = *p;
|
||||
//auto p = *p;
|
||||
|
||||
// Advance states as needed
|
||||
switch (p->rr) {
|
||||
case StoreAndForward_RequestResponse_CLIENT_ERROR:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_HISTORY:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_PING:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_PONG:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_STATS:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_BUSY:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_ERROR:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_HEARTBEAT:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_PING:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_PONG:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
assert(0); // unexpected state - FIXME, make an error code and reboot
|
||||
}
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
StoreForwardPlugin::StoreForwardPlugin()
|
||||
: SinglePortPlugin("StoreForwardPlugin", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("StoreForwardPlugin")
|
||||
: SinglePortPlugin("StoreForwardPlugin", PortNum_STORE_FORWARD_APP), concurrency::OSThread("StoreForwardPlugin")
|
||||
{
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
||||
isPromiscuous = true; // Brown chicken brown cow
|
||||
|
||||
if (StoreForward_Dev) {
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
// radioConfig.preferences.is_router = 1;
|
||||
// radioConfig.preferences.is_always_powered = 1;
|
||||
if (StoreForward_Dev) {
|
||||
radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
radioConfig.preferences.is_router = 1;
|
||||
}
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
@@ -369,11 +248,7 @@ StoreForwardPlugin::StoreForwardPlugin()
|
||||
|
||||
// Do the startup here
|
||||
|
||||
// Popupate PSRAM with our data structures.
|
||||
this->populatePSRAM();
|
||||
|
||||
this->packetTimeMax = 2000;
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
@@ -390,4 +265,4 @@ StoreForwardPlugin::StoreForwardPlugin()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user