mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-25 04:00:30 +00:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75281e8c97 | ||
|
|
8d47e4f3e0 | ||
|
|
92124e1224 | ||
|
|
c798c0032c | ||
|
|
2c5ea03b74 | ||
|
|
9d452ebf29 | ||
|
|
8a20155214 | ||
|
|
6a872b6ac2 | ||
|
|
52d61acc23 | ||
|
|
2594ea0c2c | ||
|
|
9623be1484 | ||
|
|
d810ce0c1e | ||
|
|
efd39c0f49 | ||
|
|
5f45a10db5 | ||
|
|
5f948c09fe | ||
|
|
22f3efd083 | ||
|
|
88716fc352 | ||
|
|
5c1d8b5bb0 | ||
|
|
b68397a911 | ||
|
|
5fdcb72d46 | ||
|
|
b70a359fe8 | ||
|
|
a9c8564524 | ||
|
|
b527e0d447 | ||
|
|
d8669f860a | ||
|
|
78f104c6de | ||
|
|
2f8e663f03 | ||
|
|
7f7b07ce9d | ||
|
|
cdb4756d9d | ||
|
|
385e291f51 | ||
|
|
7e60078791 | ||
|
|
073eecd147 | ||
|
|
525fe9b96c | ||
|
|
c7f411fc7c | ||
|
|
fc96500329 | ||
|
|
4e87c4411c | ||
|
|
9eb9c473db | ||
|
|
bfd147062f | ||
|
|
890ec7bdb2 | ||
|
|
76269b397f | ||
|
|
9fb6b1718f | ||
|
|
57c82988e2 | ||
|
|
1e3b037fea | ||
|
|
1e7808991d | ||
|
|
4f4cdf4f9e | ||
|
|
78f2c656d0 | ||
|
|
37ec969f96 | ||
|
|
f1a6693bb7 | ||
|
|
8ffd5a1d4f | ||
|
|
29eb5e8327 | ||
|
|
c175c21189 | ||
|
|
fc2862bd16 | ||
|
|
c9f814a9a7 | ||
|
|
92d2d3960b | ||
|
|
7872cb050d | ||
|
|
89029311c1 | ||
|
|
f6f586decb | ||
|
|
471c06b169 | ||
|
|
040bb1d1e0 | ||
|
|
bbaf5946f0 | ||
|
|
5286f23c9a | ||
|
|
7e9e33d462 | ||
|
|
04225f7bc2 | ||
|
|
dd0f1b2704 | ||
|
|
669807524e | ||
|
|
97a5405293 | ||
|
|
f298c7d053 | ||
|
|
a59f5344de | ||
|
|
13cfce48fa | ||
|
|
0261c243e0 | ||
|
|
ab325d6d2c | ||
|
|
b20930c111 | ||
|
|
770788d0a4 | ||
|
|
d02f615cad | ||
|
|
e17fe7e075 | ||
|
|
e193f63687 | ||
|
|
1eb37dded8 |
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -22,9 +22,6 @@ jobs:
|
||||
- name: Install extra python tools
|
||||
run: |
|
||||
pip install -U adafruit-nrfutil
|
||||
- name: Install libs needed for linux build
|
||||
run: |
|
||||
sudo apt install -y libpsocksxx-dev
|
||||
- name: Build for tbeam
|
||||
run: platformio run -e tbeam
|
||||
- name: Build for heltec
|
||||
@@ -36,6 +33,7 @@ jobs:
|
||||
- name: Integration test
|
||||
run: |
|
||||
.pio/build/native/program &
|
||||
sleep 1
|
||||
sleep 5
|
||||
echo "Simulator started, launching python test..."
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
|
||||
|
||||
30
.idea/workspace.xml
generated
30
.idea/workspace.xml
generated
@@ -15,16 +15,13 @@
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="58922733-b05b-4b90-9655-b9b18914977a" name="Default Changelist" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docs/software/TODO.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/software/TODO.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/proto" beforeDir="false" afterPath="$PROJECT_DIR$/proto" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/mesh/generated/mesh.pb.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/generated/mesh.pb.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/platformio.ini" beforeDir="false" afterPath="$PROJECT_DIR$/platformio.ini" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="ExecutionTargetManager" SELECTED_TARGET="CMakeBuildProfile:native" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
@@ -49,7 +46,7 @@
|
||||
<property name="node.js.selected.package.tslint" value="(autodetect)" />
|
||||
<property name="settings.editor.selected.configurable" value="CMakeSettings" />
|
||||
</component>
|
||||
<component name="RunManager" selected="PlatformIO.PlatformIO Upload">
|
||||
<component name="RunManager" selected="GDB Remote Debug.gdbremote-localhost-2345">
|
||||
<configuration default="true" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<method v="2" />
|
||||
@@ -63,9 +60,9 @@
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="GradleAppRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
|
||||
<configuration default="true" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.cpp.gradle.execution.GradleNativeBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="PlatformIO Debug" type="platformio" factoryName="PlatformIO Debug" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Debug" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Debug">
|
||||
@@ -96,6 +93,10 @@
|
||||
<workItem from="1615788663210" duration="6661000" />
|
||||
<workItem from="1615938346019" duration="1208000" />
|
||||
<workItem from="1615971126983" duration="5945000" />
|
||||
<workItem from="1617115374907" duration="357000" />
|
||||
<workItem from="1617115747078" duration="1391000" />
|
||||
<workItem from="1617117632667" duration="307000" />
|
||||
<workItem from="1617160691713" duration="1016000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
@@ -117,18 +118,23 @@
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/StreamAPI.cpp</url>
|
||||
<line>20</line>
|
||||
<option name="timeStamp" value="4" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||
<line>53</line>
|
||||
<option name="timeStamp" value="6" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||
<line>37</line>
|
||||
<option name="timeStamp" value="7" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
<watches-manager>
|
||||
<configuration name="CLion_Remote">
|
||||
<watch expression="radioConfig" language="ObjectiveC" />
|
||||
</configuration>
|
||||
</watches-manager>
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
|
||||
@@ -199,7 +199,7 @@ We'd love to have you join us on this merry little project. Please see our [deve
|
||||
|
||||
# Credits
|
||||
|
||||
This project is run by volunteers. Past contributors include:
|
||||
This project is run by volunteers. We are a friendly group and welcome any contribution (code fixes, documentation, features, bug reports etc...). We try to be good about listing contributor names in release notes, but it has become unwieldy for the main-devs to keep updating the list below and we've neglected it too long. If you'd like your name included in this list please send a pull request to edit this README and simply add your line yourself. Thank you very much for your help!
|
||||
|
||||
- @astro-arphid: Added support for 433MHz radios in europe.
|
||||
- @claesg: Various documentation fixes and 3D print enclosures
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
PYTHON=${PYTHON:-python}
|
||||
PYTHON=${PYTHON:-python3}
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
PYTHON=${PYTHON:-python}
|
||||
PYTHON=${PYTHON:-python3}
|
||||
|
||||
# Usage info
|
||||
show_help() {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
set -e
|
||||
pio run --environment native
|
||||
gdbserver --once localhost:2345 .pio/build/native/program
|
||||
gdbserver --once localhost:2345 .pio/build/native/program "$@"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
set -e
|
||||
pio run --environment native
|
||||
.pio/build/native/program
|
||||
.pio/build/native/program "$@"
|
||||
|
||||
@@ -4,11 +4,34 @@ You probably don't care about this section - skip to the next one.
|
||||
|
||||
## before next release
|
||||
|
||||
* fix heltec battery scaling
|
||||
* DONE remote admin busted?
|
||||
* DONE check android code - @havealoha comments about odd sleep behavior
|
||||
* ABANDONED test github actions locally on linux
|
||||
* DONE fix github actions per sasha tip
|
||||
* tell ttgo to preinstall new bins
|
||||
* DONE sendtext busted in portduino, due to bytetime calculations
|
||||
* remove linux dependency in native build
|
||||
* DONE tcp stream problem in python+pordtuino, server thinks client dropped when client DID NOT DROP
|
||||
* DONE TCP mode for android, localhost is at 10.0.2.2
|
||||
* make sure USB still works in android
|
||||
* add portduino builds to zip
|
||||
* add license to portduino and make announcement
|
||||
* DONE naks are being dropped (though enqueuedLocal) sometimes before phone/PC gets them
|
||||
* DONE have android fill in if local GPS has poor signal
|
||||
* optionally restrict position sends to a named channel
|
||||
* release to beta and amazon
|
||||
* add reference counting to mesh packets
|
||||
* allow multiple simultanteous phoneapi connections
|
||||
* DONE split position.time and last_heard
|
||||
* DONE update android app to use last_heard
|
||||
* DONE turn off bluetooth interface ENTIRELY while using serial API (was python client times out on connect sometimes)
|
||||
* DONE gps assistance from phone not working?
|
||||
* DONE test latest firmware update with is_router
|
||||
* DONE firmware OTA updates of is_router true nodes fails?
|
||||
* DONE add UI in android app to reset to defaults https://github.com/meshtastic/Meshtastic-Android/issues/263
|
||||
* DONE TEST THIS! changing channels requires a reboot to take effect https://github.com/meshtastic/Meshtastic-device/issues/752
|
||||
* DIBE bug report with remote info request timing out
|
||||
* DONE bug report with remote info request timing out
|
||||
* DONE retest channel changing in android (using sim?)
|
||||
* DONE move remote admin doc from forum into git
|
||||
* DONE check crashlytics
|
||||
@@ -29,6 +52,12 @@ You probably don't care about this section - skip to the next one.
|
||||
|
||||
## MQTT
|
||||
|
||||
* mqtt.meshtastic.org should have VERY basic auth at launch (to prevent abuse)
|
||||
* use MQTT for simulator mesh network
|
||||
* do initial development inside of portduino
|
||||
* do as much possible on the device side (so we can eventually just have ESP32 talk directly to server)
|
||||
* eventually add a MQTTPacket on the ToRadio & FromRadio links
|
||||
|
||||
## Multichannel support
|
||||
|
||||
* DONE cleanup the external notification and serial plugins
|
||||
@@ -111,7 +140,7 @@ You probably don't care about this section - skip to the next one.
|
||||
* DONE make all subpackets different versions of data
|
||||
* DONE move routing control into a data packet
|
||||
* have phoneapi done via plugin (will allow multiple simultaneous API clients - stop disabling BLE while using phone API)
|
||||
* use reference counting and dynamic sizing for meshpackets.
|
||||
* use reference counting and dynamic sizing for meshpackets. - use https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 (already used in arduino)
|
||||
* let multiple PhoneAPI endpoints work at once
|
||||
* allow multiple simultaneous bluetooth connections (create the bluetooth phoneapi instance dynamically based on client id)
|
||||
* DONE figure out how to add micro_delta to position, make it so that phone apps don't need to understand it?
|
||||
@@ -129,6 +158,7 @@ You probably don't care about this section - skip to the next one.
|
||||
|
||||
For app cleanup:
|
||||
|
||||
* don't store redundant User admin or position broadcasts in the ToPhone queue (only keep one per sending node per proto type, and only most recent)
|
||||
* use structured logging to kep logs in ram. Also send logs as packets to api clients
|
||||
* DONE writeup nice python options docs (common cases, link to protobuf docs)
|
||||
* have android app link to user manual
|
||||
|
||||
10
docs/software/running-github-actions.md
Normal file
10
docs/software/running-github-actions.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Running github actions locally
|
||||
|
||||
If you'd like to run the **same** integration tests we run on github but on your own machine, you can do the following.
|
||||
|
||||
1. Install homebrew per https://brew.sh/
|
||||
2. Install https://github.com/nektos/act with "brew install act"
|
||||
3. cd into meshtastic-device and run "act"
|
||||
4. Select a "medium" sized image
|
||||
5. Alas - this "act" build **almost** works, but fails because it can't find lib/nanopb/include/pb.h! So someone (you the reader? @geeksville ays hopefully...) needs to fix that before these instructions are complete.
|
||||
6.
|
||||
@@ -40,7 +40,7 @@ extra_scripts = bin/platformio-custom.py
|
||||
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
|
||||
build_flags = -Wno-missing-field-initializers
|
||||
-Wno-format
|
||||
-Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||
-DHW_VERSION_${sysenv.COUNTRY}
|
||||
-DHW_VERSION=${sysenv.HW_VERSION}
|
||||
-DUSE_THREAD_NAMES
|
||||
@@ -68,7 +68,7 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
|
||||
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
|
||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||
https://github.com/meshtastic/arduino-fsm.git#55c47b6cded91645aff05a27b6e5821d8d0f64be
|
||||
https://github.com/meshtastic/arduino-fsm.git#829e967b8a95c094f73c60ef8dacfe66eae38940
|
||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||
https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
|
||||
@@ -110,7 +110,7 @@ lib_deps =
|
||||
# board_build.ldscript = linker/esp32.extram.bss.ld
|
||||
lib_ignore = segger_rtt
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#352c8ea7cb73f10433ed139f34251979c470ad56
|
||||
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276
|
||||
|
||||
; leave this commented out to avoid breaking Windows
|
||||
upload_port = /dev/ttyUSB0
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 820fa497df...2aa1439214
@@ -40,7 +40,7 @@ bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2
|
||||
tParam1 = param1;
|
||||
tParam2 = param2;
|
||||
|
||||
timerAlarmWrite(timer, delayMsec * 1000L, false); // Do not reload, we want it to be a single shot timer
|
||||
timerAlarmWrite(timer, delayMsec * 1000UL, false); // Do not reload, we want it to be a single shot timer
|
||||
timerRestart(timer);
|
||||
timerAlarmEnable(timer);
|
||||
return true;
|
||||
|
||||
@@ -9,6 +9,23 @@
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
|
||||
/// Should we behave as if we have AC power now?
|
||||
static bool isPowered()
|
||||
{
|
||||
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
|
||||
// We assume routers might be powered all the time, but from a low current (solar) source
|
||||
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
|
||||
|
||||
/* To determine if we're externally powered, assumptions
|
||||
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
|
||||
|
||||
2) If we detect USB power from the power management chip, we must be getting power externally.
|
||||
*/
|
||||
return !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||
}
|
||||
|
||||
static void sdsEnter()
|
||||
{
|
||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||
@@ -119,14 +136,34 @@ static void serialEnter()
|
||||
{
|
||||
setBluetoothEnable(false);
|
||||
screen->setOn(true);
|
||||
screen->print("Using API...\n");
|
||||
screen->print("Serial connected\n");
|
||||
}
|
||||
|
||||
static void serialExit()
|
||||
{
|
||||
screen->print("Serial disconnected\n");
|
||||
}
|
||||
|
||||
static void powerEnter()
|
||||
{
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
screen->print("Powered...\n");
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||
DEBUG_MSG("Loss of power in Powered\n");
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
} else {
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
screen->print("Powered...\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void powerIdle()
|
||||
{
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state
|
||||
DEBUG_MSG("Loss of power in Powered\n");
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void powerExit()
|
||||
@@ -153,6 +190,14 @@ static void onEnter()
|
||||
}
|
||||
}
|
||||
|
||||
static void onIdle()
|
||||
{
|
||||
if (isPowered()) {
|
||||
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void screenPress()
|
||||
{
|
||||
screen->onPress();
|
||||
@@ -164,26 +209,16 @@ State stateSDS(sdsEnter, NULL, NULL, "SDS");
|
||||
State stateLS(lsEnter, lsIdle, lsExit, "LS");
|
||||
State stateNB(nbEnter, NULL, NULL, "NB");
|
||||
State stateDARK(darkEnter, NULL, NULL, "DARK");
|
||||
State stateSERIAL(serialEnter, NULL, NULL, "SERIAL");
|
||||
State stateSERIAL(serialEnter, NULL, serialExit, "SERIAL");
|
||||
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
|
||||
State stateON(onEnter, NULL, NULL, "ON");
|
||||
State statePOWER(powerEnter, NULL, powerExit, "POWER");
|
||||
State stateON(onEnter, onIdle, NULL, "ON");
|
||||
State statePOWER(powerEnter, powerIdle, powerExit, "POWER");
|
||||
Fsm powerFSM(&stateBOOT);
|
||||
|
||||
void PowerFSM_setup()
|
||||
{
|
||||
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
|
||||
// We assume routers might be powered all the time, but from a low current (solar) source
|
||||
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
|
||||
|
||||
/* To determine if we're externally powered, assumptions
|
||||
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
|
||||
|
||||
2) If we detect USB power from the power management chip, we must be getting power externally.
|
||||
*/
|
||||
bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||
bool hasPower = isPowered();
|
||||
|
||||
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
|
||||
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
|
||||
@@ -231,22 +266,25 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
|
||||
}
|
||||
|
||||
// If we are not in statePOWER but get a serial connection, suppress sleep (and keep the screen on) while connected
|
||||
powerFSM.add_transition(&stateLS, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
powerFSM.add_transition(&stateNB, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
powerFSM.add_transition(&statePOWER, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
|
||||
if (!isLowPower) {
|
||||
powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
}
|
||||
// If we get power connected, go to the power connect state
|
||||
powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
|
||||
|
||||
powerFSM.add_transition(&statePOWER, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
|
||||
powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
|
||||
// powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
|
||||
|
||||
powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
|
||||
// the only way to leave state serial is for the client to disconnect (or we timeout and force disconnect them)
|
||||
// when we leave, go to ON (which might not be the correct state if we have power connected, we will fix that in onEnter)
|
||||
powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
|
||||
|
||||
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
||||
|
||||
@@ -265,7 +303,9 @@ void PowerFSM_setup()
|
||||
#ifndef NRF52_SERIES
|
||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
|
||||
// I don't think this transition is correct, turning off for now - @geeksville
|
||||
// powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
|
||||
|
||||
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
|
||||
#else
|
||||
|
||||
@@ -40,7 +40,7 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
va_end(arg);
|
||||
return 0;
|
||||
};
|
||||
if (len >= printBufLen) {
|
||||
if (len >= (int)printBufLen) {
|
||||
delete[] printBuf;
|
||||
printBufLen *= 2;
|
||||
printBuf = new char[printBufLen];
|
||||
|
||||
@@ -6,27 +6,29 @@
|
||||
|
||||
#define Port Serial
|
||||
|
||||
SerialConsole console;
|
||||
SerialConsole *console;
|
||||
|
||||
void consoleInit()
|
||||
{
|
||||
new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
|
||||
}
|
||||
|
||||
void consolePrintf(const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
console.vprintf(format, arg);
|
||||
console->vprintf(format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
{
|
||||
assert(!console);
|
||||
console = this;
|
||||
canWrite = false; // We don't send packets to our port until it has talked to us first
|
||||
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
||||
}
|
||||
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
||||
|
||||
/// Do late init that can't happen at constructor time
|
||||
void SerialConsole::init()
|
||||
{
|
||||
Port.begin(SERIAL_BAUD);
|
||||
StreamAPI::init();
|
||||
emitRebooted();
|
||||
}
|
||||
|
||||
@@ -34,14 +36,14 @@ void SerialConsole::init()
|
||||
* we override this to notice when we've received a protobuf over the serial
|
||||
* stream. Then we shunt off debug serial output.
|
||||
*/
|
||||
void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||
bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||
{
|
||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||
if (!radioConfig.preferences.debug_log_enabled)
|
||||
setDestination(&noopPrint);
|
||||
canWrite = true;
|
||||
|
||||
StreamAPI::handleToRadio(buf, len);
|
||||
return StreamAPI::handleToRadio(buf, len);
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
|
||||
@@ -11,14 +11,11 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
public:
|
||||
SerialConsole();
|
||||
|
||||
/// Do late init that can't happen at constructor time
|
||||
virtual void init();
|
||||
|
||||
/**
|
||||
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
|
||||
* debug serial output.
|
||||
*/
|
||||
virtual void handleToRadio(const uint8_t *buf, size_t len);
|
||||
virtual bool handleToRadio(const uint8_t *buf, size_t len);
|
||||
|
||||
virtual size_t write(uint8_t c)
|
||||
{
|
||||
@@ -34,5 +31,6 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
|
||||
// A simple wrapper to allow non class aware code write to the console
|
||||
void consolePrintf(const char *format, ...);
|
||||
void consoleInit();
|
||||
|
||||
extern SerialConsole console;
|
||||
extern SerialConsole *console;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
#include "../freertosinc.h"
|
||||
|
||||
namespace concurrency
|
||||
@@ -28,4 +27,4 @@ class BinarySemaphoreFreeRTOS
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace concurrency
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
#include "../freertosinc.h"
|
||||
|
||||
namespace concurrency
|
||||
@@ -28,4 +27,4 @@ class BinarySemaphorePosix
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace concurrency
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "NotifiedWorkerThread.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace concurrency
|
||||
@@ -28,6 +29,7 @@ IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
|
||||
if (overwrite || notification == 0) {
|
||||
enabled = true;
|
||||
setInterval(0); // Run ASAP
|
||||
runASAP = true;
|
||||
|
||||
notification = v;
|
||||
if (debugNotification)
|
||||
|
||||
@@ -457,7 +457,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "SerialConsole.h"
|
||||
|
||||
#define DEBUG_PORT console // Serial debug port
|
||||
#define DEBUG_PORT (*console) // Serial debug port
|
||||
|
||||
// What platforms should use SEGGER?
|
||||
#ifdef NRF52_SERIES
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
int16_t updateResultHandle = -1;
|
||||
|
||||
static CRC32 crc;
|
||||
static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
|
||||
|
||||
static uint32_t updateExpectedSize, updateActualSize;
|
||||
static uint8_t update_result;
|
||||
@@ -139,14 +138,6 @@ int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct bl
|
||||
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
|
||||
}
|
||||
|
||||
void bluetoothRebootCheck()
|
||||
{
|
||||
if (rebootAtMsec && millis() > rebootAtMsec) {
|
||||
DEBUG_MSG("Rebooting for update\n");
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
See bluetooth-api.md
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
void reinitUpdateService();
|
||||
|
||||
void bluetoothRebootCheck();
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
#include <Preferences.h>
|
||||
#include <driver/rtc_io.h>
|
||||
#include <nvs.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
@@ -45,6 +46,18 @@ void esp32Setup()
|
||||
DEBUG_MSG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d\n", nvs_stats.used_entries, nvs_stats.free_entries,
|
||||
nvs_stats.total_entries);
|
||||
|
||||
DEBUG_MSG("Setup Preferences in Flash Storage\n");
|
||||
|
||||
// Create object to store our persistant data
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
|
||||
uint32_t rebootCounter = preferences.getUInt("rebootCounter", 0);
|
||||
rebootCounter++;
|
||||
preferences.putUInt("rebootCounter", rebootCounter);
|
||||
preferences.end();
|
||||
DEBUG_MSG("Number of Device Reboots: %d\n", rebootCounter);
|
||||
|
||||
// enableModemSleep();
|
||||
|
||||
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
|
||||
@@ -84,7 +97,6 @@ void esp32Loop()
|
||||
{
|
||||
esp_task_wdt_reset(); // service our app level watchdog
|
||||
loopBLE();
|
||||
bluetoothRebootCheck();
|
||||
|
||||
// for debug printing
|
||||
// radio.radioIf.canSleep();
|
||||
|
||||
@@ -39,7 +39,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
currentQuality = q;
|
||||
shouldSet = true;
|
||||
DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
|
||||
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) {
|
||||
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
|
||||
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
|
||||
shouldSet = true;
|
||||
DEBUG_MSG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
|
||||
|
||||
@@ -717,6 +717,7 @@ void Screen::handleSetOn(bool on)
|
||||
dispdev.displayOn();
|
||||
enabled = true;
|
||||
setInterval(0); // Draw ASAP
|
||||
runASAP = true;
|
||||
} else {
|
||||
DEBUG_MSG("Turning off screen\n");
|
||||
dispdev.displayOff();
|
||||
@@ -1053,6 +1054,7 @@ void Screen::setFastFramerate()
|
||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
setInterval(0); // redraw ASAP
|
||||
runASAP = true;
|
||||
}
|
||||
|
||||
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
|
||||
52
src/main.cpp
52
src/main.cpp
@@ -177,6 +177,7 @@ class ButtonThread : public OSThread
|
||||
OneButton userButtonAlt;
|
||||
#endif
|
||||
static bool shutdown_on_long_stop;
|
||||
|
||||
public:
|
||||
static uint32_t longPressTime;
|
||||
|
||||
@@ -250,15 +251,15 @@ class ButtonThread : public OSThread
|
||||
power->shutdown();
|
||||
}
|
||||
#elif NRF52_SERIES
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
if (!shutdown_on_long_stop) {
|
||||
DEBUG_MSG("Shutdown from long press");
|
||||
playBeep();
|
||||
ledOff(PIN_LED1);
|
||||
ledOff(PIN_LED2);
|
||||
shutdown_on_long_stop = true;
|
||||
}
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
if (!shutdown_on_long_stop) {
|
||||
DEBUG_MSG("Shutdown from long press");
|
||||
playBeep();
|
||||
ledOff(PIN_LED1);
|
||||
ledOff(PIN_LED2);
|
||||
shutdown_on_long_stop = true;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
|
||||
@@ -315,9 +316,10 @@ void setup()
|
||||
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
||||
#endif
|
||||
|
||||
// Debug
|
||||
#ifdef DEBUG_PORT
|
||||
DEBUG_PORT.init(); // Set serial baud rate and init our mesh console
|
||||
if (!radioConfig.preferences.serial_disabled) {
|
||||
consoleInit(); // Set serial baud rate and init our mesh console
|
||||
}
|
||||
#endif
|
||||
|
||||
initDeepSleep();
|
||||
@@ -576,13 +578,29 @@ Periodic axpDebugOutput(axpDebugRead);
|
||||
axpDebugOutput.setup();
|
||||
#endif
|
||||
|
||||
uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
|
||||
|
||||
void rebootCheck()
|
||||
{
|
||||
if (rebootAtMsec && millis() > rebootAtMsec) {
|
||||
#ifndef NO_ESP32
|
||||
DEBUG_MSG("Rebooting for update\n");
|
||||
ESP.restart();
|
||||
#else
|
||||
DEBUG_MSG("FIXME implement reboot for this platform");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
bool runASAP;
|
||||
|
||||
void loop()
|
||||
{
|
||||
// axpDebugOutput.loop();
|
||||
runASAP = false;
|
||||
|
||||
#ifdef DEBUG_PORT
|
||||
DEBUG_PORT.loop(); // Send/receive protobufs over the serial port
|
||||
#endif
|
||||
// axpDebugOutput.loop();
|
||||
|
||||
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
|
||||
|
||||
@@ -592,6 +610,7 @@ void loop()
|
||||
#ifdef NRF52_SERIES
|
||||
nrf52Loop();
|
||||
#endif
|
||||
rebootCheck();
|
||||
|
||||
// For debugging
|
||||
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
|
||||
@@ -616,6 +635,7 @@ void loop()
|
||||
mainController.nextThread->tillRun(millis())); */
|
||||
|
||||
// We want to sleep as long as possible here - because it saves power
|
||||
mainDelay.delay(delayMsec);
|
||||
if (!runASAP)
|
||||
mainDelay.delay(delayMsec);
|
||||
// if (didWake) DEBUG_MSG("wake!\n");
|
||||
}
|
||||
|
||||
@@ -20,4 +20,10 @@ extern graphics::Screen *screen;
|
||||
// Return a human readable string of the form "Meshtastic_ab13"
|
||||
const char *getDeviceName();
|
||||
|
||||
extern uint32_t rebootAtMsec;
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop();
|
||||
|
||||
@@ -36,6 +36,7 @@ MeshPacket *MeshPlugin::allocAckNak(Routing_Error err, NodeNum to, PacketId idFr
|
||||
Routing c = Routing_init_default;
|
||||
|
||||
c.error_reason = err;
|
||||
c.which_variant = Routing_error_reason_tag;
|
||||
|
||||
// Now that we have moded sendAckNak up one level into the class heirarchy we can no longer assume we are a RoutingPlugin
|
||||
// So we manually call pb_encode_to_bytes and specify routing port number
|
||||
|
||||
@@ -114,7 +114,7 @@ bool MeshService::reloadConfig()
|
||||
void MeshService::reloadOwner()
|
||||
{
|
||||
assert(nodeInfoPlugin);
|
||||
if(nodeInfoPlugin)
|
||||
if (nodeInfoPlugin)
|
||||
nodeInfoPlugin->sendOurNodeInfo();
|
||||
nodeDB.saveToDisk();
|
||||
}
|
||||
@@ -172,13 +172,12 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
assert(node);
|
||||
|
||||
if (node->has_position) {
|
||||
if(positionPlugin) {
|
||||
if (positionPlugin) {
|
||||
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
positionPlugin->sendOurPosition(dest, wantReplies);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(nodeInfoPlugin) {
|
||||
} else {
|
||||
if (nodeInfoPlugin) {
|
||||
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
|
||||
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
|
||||
}
|
||||
@@ -198,10 +197,13 @@ NodeInfo *MeshService::refreshMyNodeInfo()
|
||||
|
||||
Position &position = node->position;
|
||||
|
||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||
position.time =
|
||||
// Update our local node info with our time (even if we don't decide to update anyone else)
|
||||
node->last_heard =
|
||||
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
|
||||
|
||||
// For the time in the position field, only set that if we have a real GPS clock
|
||||
position.time = getValidTime(RTCQualityGPS);
|
||||
|
||||
position.battery_level = powerStatus->getBatteryChargePercent();
|
||||
updateBatteryLevel(position.battery_level);
|
||||
|
||||
|
||||
@@ -84,13 +84,12 @@ class MeshService
|
||||
NodeInfo *refreshMyNodeInfo();
|
||||
|
||||
private:
|
||||
|
||||
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
||||
/// returns 0 to allow futher processing
|
||||
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
||||
|
||||
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it needs
|
||||
/// to keep the packet around it makes a copy
|
||||
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
|
||||
/// needs to keep the packet around it makes a copy
|
||||
int handleFromRadio(const MeshPacket *p);
|
||||
friend class RoutingPlugin;
|
||||
};
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "plugins/esp32/StoreForwardPlugin.h"
|
||||
#include <Preferences.h>
|
||||
#endif
|
||||
|
||||
NodeDB nodeDB;
|
||||
@@ -233,6 +235,15 @@ void NodeDB::init()
|
||||
myNodeInfo.hw_model_deprecated[0] = '\0';
|
||||
// strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model));
|
||||
|
||||
#ifndef NO_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
|
||||
preferences.end();
|
||||
DEBUG_MSG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||
|
||||
#endif
|
||||
|
||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||
|
||||
DEBUG_MSG("region=%d, NODENUM=0x%x, dbsize=%d\n", radioConfig.preferences.region, myNodeInfo.my_node_num, *numNodes);
|
||||
@@ -408,8 +419,7 @@ uint32_t sinceLastSeen(const NodeInfo *n)
|
||||
{
|
||||
uint32_t now = getTime();
|
||||
|
||||
uint32_t last_seen = n->position.time;
|
||||
int delta = (int)(now - last_seen);
|
||||
int delta = (int)(now - n->last_heard);
|
||||
if (delta < 0) // our clock must be slightly off still - not set from GPS yet
|
||||
delta = 0;
|
||||
|
||||
@@ -443,7 +453,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
|
||||
// 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 (!info->position.time && p.time)
|
||||
if (p.time)
|
||||
info->position.time = p.time;
|
||||
if (p.battery_level)
|
||||
info->position.battery_level = p.battery_level;
|
||||
@@ -451,6 +461,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
|
||||
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
|
||||
@@ -491,10 +503,8 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
|
||||
NodeInfo *info = getOrCreateNode(getFrom(&mp));
|
||||
|
||||
if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
|
||||
info->has_position = true; // at least the time is valid
|
||||
info->position.time = mp.rx_time;
|
||||
}
|
||||
if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard
|
||||
info->last_heard = mp.rx_time;
|
||||
|
||||
if (mp.rx_snr)
|
||||
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "PhoneAPI.h"
|
||||
#include "Channels.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "Channels.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
|
||||
@@ -15,33 +15,52 @@
|
||||
#error ToRadio is too big
|
||||
#endif
|
||||
|
||||
PhoneAPI::PhoneAPI() {}
|
||||
|
||||
void PhoneAPI::init()
|
||||
PhoneAPI::PhoneAPI()
|
||||
{
|
||||
observe(&service.fromNumChanged);
|
||||
lastContactMsec = millis();
|
||||
}
|
||||
|
||||
PhoneAPI::~PhoneAPI() {
|
||||
PhoneAPI::~PhoneAPI()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void PhoneAPI::close() {
|
||||
unobserve();
|
||||
state = STATE_SEND_NOTHING;
|
||||
bool oldConnected = isConnected;
|
||||
isConnected = false;
|
||||
if(oldConnected != isConnected)
|
||||
onConnectionChanged(isConnected);
|
||||
void PhoneAPI::handleStartConfig()
|
||||
{
|
||||
if (!isConnected()) {
|
||||
onConnectionChanged(true);
|
||||
observe(&service.fromNumChanged);
|
||||
}
|
||||
|
||||
// even if we were already connected - restart our state machine
|
||||
state = STATE_SEND_MY_INFO;
|
||||
|
||||
DEBUG_MSG("Reset nodeinfo read pointer\n");
|
||||
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
|
||||
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
|
||||
// this will break once we have multiple instances of PhoneAPI running independently
|
||||
}
|
||||
|
||||
void PhoneAPI::close()
|
||||
{
|
||||
if (state != STATE_SEND_NOTHING) {
|
||||
state = STATE_SEND_NOTHING;
|
||||
|
||||
unobserve();
|
||||
releasePhonePacket(); // Don't leak phone packets on shutdown
|
||||
|
||||
onConnectionChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneAPI::checkConnectionTimeout()
|
||||
{
|
||||
if (isConnected) {
|
||||
bool newConnected = (millis() - lastContactMsec < getPref_phone_timeout_secs() * 1000L);
|
||||
if (!newConnected) {
|
||||
isConnected = false;
|
||||
onConnectionChanged(isConnected);
|
||||
if (isConnected()) {
|
||||
uint32_t now = millis();
|
||||
bool newContact = (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL;
|
||||
if (!newContact) {
|
||||
DEBUG_MSG("Timed out on phone contact, dropping phone connection\n");
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,34 +68,28 @@ void PhoneAPI::checkConnectionTimeout()
|
||||
/**
|
||||
* Handle a ToRadio protobuf
|
||||
*/
|
||||
void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
{
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
|
||||
lastContactMsec = millis();
|
||||
if (!isConnected) {
|
||||
isConnected = true;
|
||||
onConnectionChanged(isConnected);
|
||||
}
|
||||
|
||||
// return (lastContactMsec != 0) &&
|
||||
|
||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
||||
switch (toRadioScratch.which_payloadVariant) {
|
||||
case ToRadio_packet_tag: {
|
||||
MeshPacket &p = toRadioScratch.packet;
|
||||
printPacket("PACKET FROM PHONE", &p);
|
||||
service.handleToRadio(p);
|
||||
break;
|
||||
}
|
||||
case ToRadio_packet_tag:
|
||||
return handleToRadioPacket(toRadioScratch.packet);
|
||||
|
||||
case ToRadio_want_config_id_tag:
|
||||
config_nonce = toRadioScratch.want_config_id;
|
||||
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
|
||||
state = STATE_SEND_MY_INFO;
|
||||
|
||||
DEBUG_MSG("Reset nodeinfo read pointer\n");
|
||||
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
|
||||
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
|
||||
// this will break once we have multiple instances of PhoneAPI running independently
|
||||
handleStartConfig();
|
||||
break;
|
||||
|
||||
case ToRadio_disconnect_tag:
|
||||
close();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -86,6 +99,8 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
} else {
|
||||
DEBUG_MSG("Error: ignoring malformed toradio\n");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,14 +135,12 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
case STATE_SEND_MY_INFO:
|
||||
// If the user has specified they don't want our node to share its location, make sure to tell the phone
|
||||
// app not to send locations on our behalf.
|
||||
myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled)
|
||||
? true
|
||||
: (gps && gps->isConnected()); // Update with latest GPS connect info
|
||||
myNodeInfo.has_gps = gps && gps->isConnected(); // Update with latest GPS connect info
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
|
||||
fromRadioScratch.my_info = myNodeInfo;
|
||||
state = STATE_SEND_NODEINFO;
|
||||
|
||||
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
|
||||
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
|
||||
break;
|
||||
|
||||
case STATE_SEND_NODEINFO: {
|
||||
@@ -135,7 +148,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
|
||||
|
||||
if (info) {
|
||||
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
|
||||
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->last_heard, info->user.id,
|
||||
info->user.long_name);
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
|
||||
fromRadioScratch.node_info = *info;
|
||||
@@ -159,16 +172,13 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
case STATE_SEND_PACKETS:
|
||||
// Do we have a message from the mesh?
|
||||
if (packetForPhone) {
|
||||
|
||||
printPacket("phone downloaded packet", packetForPhone);
|
||||
|
||||
// Encapsulate as a FromRadio packet
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
|
||||
fromRadioScratch.packet = *packetForPhone;
|
||||
|
||||
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
|
||||
packetForPhone = NULL;
|
||||
}
|
||||
releasePhonePacket();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -187,6 +197,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PhoneAPI::handleDisconnect() {}
|
||||
|
||||
void PhoneAPI::releasePhonePacket()
|
||||
{
|
||||
if (packetForPhone) {
|
||||
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
|
||||
packetForPhone = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we have data available to send to the phone
|
||||
*/
|
||||
@@ -226,7 +246,13 @@ bool PhoneAPI::available()
|
||||
/**
|
||||
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
|
||||
*/
|
||||
void PhoneAPI::handleToRadioPacket(MeshPacket *p) {}
|
||||
bool PhoneAPI::handleToRadioPacket(MeshPacket &p)
|
||||
{
|
||||
printPacket("PACKET FROM PHONE", &p);
|
||||
service.handleToRadio(p);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||
int PhoneAPI::onNotify(uint32_t newValue)
|
||||
|
||||
@@ -22,6 +22,7 @@ class PhoneAPI
|
||||
enum State {
|
||||
STATE_UNUSED, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API
|
||||
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
|
||||
// (disconnected)
|
||||
STATE_SEND_MY_INFO, // send our my info record
|
||||
// STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet
|
||||
// STATE_SEND_OWNER, no need to send Owner specially, it is just part of the nodedb
|
||||
@@ -58,17 +59,15 @@ class PhoneAPI
|
||||
/// Destructor - calls close()
|
||||
virtual ~PhoneAPI();
|
||||
|
||||
/// Do late init that can't happen at constructor time
|
||||
virtual void init();
|
||||
|
||||
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
|
||||
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
|
||||
virtual void close();
|
||||
|
||||
/**
|
||||
* Handle a ToRadio protobuf
|
||||
* @return true true if a packet was queued for sending (so that caller can yield)
|
||||
*/
|
||||
virtual void handleToRadio(const uint8_t *buf, size_t len);
|
||||
virtual bool handleToRadio(const uint8_t *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Get the next packet we want to send to the phone
|
||||
@@ -83,17 +82,16 @@ class PhoneAPI
|
||||
*/
|
||||
bool available();
|
||||
|
||||
protected:
|
||||
/// Are we currently connected to a client?
|
||||
bool isConnected = false;
|
||||
bool isConnected() { return state != STATE_SEND_NOTHING; }
|
||||
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
FromRadio fromRadioScratch;
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected) {}
|
||||
|
||||
/// If we haven't heard from the other side in a while then say not connected
|
||||
/// If we haven't heard from the other side in a while then say not connected
|
||||
void checkConnectionTimeout();
|
||||
|
||||
/**
|
||||
@@ -101,11 +99,22 @@ class PhoneAPI
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum) {}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
|
||||
* Subclasses can use this to find out when a client drops the link
|
||||
*/
|
||||
void handleToRadioPacket(MeshPacket *p);
|
||||
virtual void handleDisconnect();
|
||||
|
||||
private:
|
||||
void releasePhonePacket();
|
||||
|
||||
/// begin a new connection
|
||||
void handleStartConfig();
|
||||
|
||||
/**
|
||||
* Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
|
||||
* @return true true if a packet was queued for sending
|
||||
*/
|
||||
bool handleToRadioPacket(MeshPacket &p);
|
||||
|
||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||
virtual int onNotify(uint32_t newValue);
|
||||
|
||||
@@ -36,8 +36,6 @@ bool RF95Interface::init()
|
||||
{
|
||||
RadioLibInterface::init();
|
||||
|
||||
applyModemConfig();
|
||||
|
||||
if (power == 0)
|
||||
power = POWER_DEFAULT;
|
||||
|
||||
@@ -86,24 +84,25 @@ void INTERRUPT_ATTR RF95Interface::disableInterrupt()
|
||||
lora->clearDio0Action();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RF95Interface::reconfigure()
|
||||
{
|
||||
applyModemConfig();
|
||||
RadioLibInterface::reconfigure();
|
||||
|
||||
// set mode to standby
|
||||
setStandby();
|
||||
|
||||
// configure publicly accessible settings
|
||||
int err = lora->setSpreadingFactor(sf);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setBandwidth(bw);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setCodingRate(cr);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setSyncWord(syncWord);
|
||||
assert(err == ERR_NONE);
|
||||
@@ -115,12 +114,14 @@ bool RF95Interface::reconfigure()
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora->setFrequency(freq);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > MAX_POWER) // This chip has lower power limits than some
|
||||
power = MAX_POWER;
|
||||
err = lora->setOutputPower(power);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
startReceive(); // restart receiving
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "Channels.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "assert.h"
|
||||
#include "Router.h"
|
||||
#include "assert.h"
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
#include <pb_decode.h>
|
||||
@@ -31,8 +31,8 @@ const RegionInfo regions[] = {
|
||||
|
||||
/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2):
|
||||
|
||||
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018) https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1
|
||||
We have 3 options for 868 MHz:
|
||||
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018)
|
||||
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1 We have 3 options for 868 MHz:
|
||||
|
||||
864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports.
|
||||
866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports
|
||||
@@ -112,6 +112,8 @@ uint32_t RadioInterface::getPacketTime(MeshPacket *p)
|
||||
/** The delay to use for retransmitting dropped packets */
|
||||
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||
{
|
||||
assert(shortPacketMsec); // Better be non zero
|
||||
|
||||
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range
|
||||
return random(9 * shortPacketMsec, 10 * shortPacketMsec);
|
||||
}
|
||||
@@ -153,7 +155,7 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
if (s.dest != 0)
|
||||
DEBUG_MSG(" dest=%08x", s.dest);
|
||||
|
||||
if(s.request_id)
|
||||
if (s.request_id)
|
||||
DEBUG_MSG(" requestId=%0x", s.request_id);
|
||||
|
||||
/* now inside Data and therefore kinda opaque
|
||||
@@ -185,6 +187,12 @@ RadioInterface::RadioInterface()
|
||||
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
|
||||
}
|
||||
|
||||
bool RadioInterface::reconfigure()
|
||||
{
|
||||
applyModemConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RadioInterface::init()
|
||||
{
|
||||
DEBUG_MSG("Starting meshradio init...\n");
|
||||
@@ -197,6 +205,8 @@ bool RadioInterface::init()
|
||||
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
|
||||
// time.
|
||||
|
||||
applyModemConfig();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -309,7 +319,7 @@ 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;
|
||||
freq = myRegion->freq + myRegion->spacing * channel_num;
|
||||
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);
|
||||
|
||||
@@ -104,7 +104,11 @@ class RadioInterface
|
||||
virtual bool sleep() { return true; }
|
||||
|
||||
/// Disable this interface (while disabled, no packets can be sent or received)
|
||||
void disable() { disabled = true; sleep(); }
|
||||
void disable()
|
||||
{
|
||||
disabled = true;
|
||||
sleep();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet (possibly by enquing in a private fifo). This routine will
|
||||
@@ -126,7 +130,7 @@ class RadioInterface
|
||||
/// Apply any radio provisioning changes
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool reconfigure() = 0;
|
||||
virtual bool reconfigure();
|
||||
|
||||
/** The delay to use for retransmitting dropped packets */
|
||||
uint32_t getRetransmissionMsec(const MeshPacket *p);
|
||||
@@ -174,13 +178,6 @@ class RadioInterface
|
||||
*/
|
||||
void limitPower();
|
||||
|
||||
/**
|
||||
* Convert our modemConfig enum into wf, sf, etc...
|
||||
*
|
||||
* These paramaters will be pull from the channelSettings global
|
||||
*/
|
||||
virtual void applyModemConfig();
|
||||
|
||||
/**
|
||||
* Save the frequency we selected for later reuse.
|
||||
*/
|
||||
@@ -192,6 +189,13 @@ class RadioInterface
|
||||
virtual void saveChannelNum(uint32_t savedChannelNum);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Convert our modemConfig enum into wf, sf, etc...
|
||||
*
|
||||
* These paramaters will be pull from the channelSettings global
|
||||
*/
|
||||
void applyModemConfig();
|
||||
|
||||
/// Return 0 if sleep is okay
|
||||
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }
|
||||
|
||||
@@ -208,18 +212,6 @@ class SimRadio : public RadioInterface
|
||||
{
|
||||
public:
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
|
||||
// methods from radiohead
|
||||
|
||||
/// 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() { return true; }
|
||||
|
||||
/// Apply any radio provisioning changes
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool reconfigure() { return true; }
|
||||
};
|
||||
|
||||
/// Debug printing for packets
|
||||
|
||||
@@ -79,9 +79,10 @@ class ReliableRouter : public FloodingRouter
|
||||
/** Do our retransmission handling */
|
||||
virtual int32_t runOnce()
|
||||
{
|
||||
auto d = FloodingRouter::runOnce();
|
||||
// Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation
|
||||
auto d = doRetransmissions();
|
||||
|
||||
int32_t r = doRetransmissions();
|
||||
int32_t r = FloodingRouter::runOnce();
|
||||
|
||||
return min(d, r);
|
||||
}
|
||||
@@ -109,7 +110,6 @@ class ReliableRouter : public FloodingRouter
|
||||
PendingPacket *startRetransmission(MeshPacket *p);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Stop any retransmissions we are doing of the specified node/packet ID pair
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
|
||||
@@ -55,9 +56,11 @@ int32_t Router::runOnce()
|
||||
{
|
||||
MeshPacket *mp;
|
||||
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) {
|
||||
// printPacket("handle fromRadioQ", mp);
|
||||
perhapsHandleReceived(mp);
|
||||
}
|
||||
|
||||
// DEBUG_MSG("sleeping forever!\n");
|
||||
return INT32_MAX; // Wait a long time - until we get woken for the message queue
|
||||
}
|
||||
|
||||
@@ -117,7 +120,9 @@ void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
||||
|
||||
void Router::setReceivedMessage()
|
||||
{
|
||||
// DEBUG_MSG("set interval to ASAP\n");
|
||||
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
|
||||
runASAP = true;
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
|
||||
@@ -23,8 +23,6 @@ bool SX1262Interface::init()
|
||||
pinMode(SX1262_POWER_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
RadioLibInterface::init();
|
||||
|
||||
#ifdef SX1262_RXEN // set not rx or tx mode
|
||||
digitalWrite(SX1262_RXEN, LOW); // Set low before becoming an output
|
||||
pinMode(SX1262_RXEN, OUTPUT);
|
||||
@@ -38,11 +36,11 @@ bool SX1262Interface::init()
|
||||
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;
|
||||
float tcxoVoltage = 1.8;
|
||||
#endif
|
||||
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
|
||||
|
||||
applyModemConfig();
|
||||
RadioLibInterface::init();
|
||||
|
||||
if (power == 0)
|
||||
power = SX1262_MAX_POWER;
|
||||
@@ -72,20 +70,23 @@ bool SX1262Interface::init()
|
||||
|
||||
bool SX1262Interface::reconfigure()
|
||||
{
|
||||
applyModemConfig();
|
||||
RadioLibInterface::reconfigure();
|
||||
|
||||
// set mode to standby
|
||||
setStandby();
|
||||
|
||||
// configure publicly accessible settings
|
||||
int err = lora.setSpreadingFactor(sf);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setBandwidth(bw);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setCodingRate(cr);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
|
||||
err = lora.setRxGain(true);
|
||||
@@ -101,7 +102,8 @@ bool SX1262Interface::reconfigure()
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
err = lora.setFrequency(freq);
|
||||
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
|
||||
@@ -5,48 +5,62 @@
|
||||
#define START2 0xc3
|
||||
#define HEADER_LEN 4
|
||||
|
||||
void StreamAPI::loop()
|
||||
int32_t StreamAPI::runOnce()
|
||||
{
|
||||
auto result = readStream();
|
||||
writeStream();
|
||||
readStream();
|
||||
checkConnectionTimeout();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read any rx chars from the link and call handleToRadio
|
||||
*/
|
||||
void StreamAPI::readStream()
|
||||
int32_t StreamAPI::readStream()
|
||||
{
|
||||
while (stream->available()) { // Currently we never want to block
|
||||
uint8_t c = stream->read();
|
||||
uint32_t now = millis();
|
||||
if (!stream->available()) {
|
||||
// Nothing available this time, if the computer has talked to us recently, poll often, otherwise let CPU sleep a long time
|
||||
bool recentRx = (now - lastRxMsec) < 2000;
|
||||
return recentRx ? 5 : 250;
|
||||
} else {
|
||||
while (stream->available()) { // Currently we never want to block
|
||||
uint8_t c = stream->read();
|
||||
|
||||
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
|
||||
size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
|
||||
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
|
||||
size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
|
||||
|
||||
rxBuf[ptr] = c; // store all bytes (including framing)
|
||||
rxBuf[ptr] = c; // store all bytes (including framing)
|
||||
|
||||
if (ptr == 0) { // looking for START1
|
||||
if (c != START1)
|
||||
rxPtr = 0; // failed to find framing
|
||||
} else if (ptr == 1) { // looking for START2
|
||||
if (c != START2)
|
||||
rxPtr = 0; // failed to find framing
|
||||
} else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
|
||||
uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
|
||||
if (ptr == 0) { // looking for START1
|
||||
if (c != START1)
|
||||
rxPtr = 0; // failed to find framing
|
||||
} else if (ptr == 1) { // looking for START2
|
||||
if (c != START2)
|
||||
rxPtr = 0; // failed to find framing
|
||||
} else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
|
||||
uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
|
||||
|
||||
if (ptr == HEADER_LEN) {
|
||||
// we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
|
||||
// protobuf also)
|
||||
if (len > MAX_TO_FROM_RADIO_SIZE)
|
||||
rxPtr = 0; // length is bogus, restart search for framing
|
||||
}
|
||||
if (ptr == HEADER_LEN) {
|
||||
// we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
|
||||
// protobuf also)
|
||||
if (len > MAX_TO_FROM_RADIO_SIZE)
|
||||
rxPtr = 0; // length is bogus, restart search for framing
|
||||
}
|
||||
|
||||
if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
|
||||
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
||||
handleToRadio(rxBuf + HEADER_LEN, len);
|
||||
rxPtr = 0; // start over again
|
||||
if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
|
||||
rxPtr = 0; // start over again on the next packet
|
||||
|
||||
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
||||
if (handleToRadio(rxBuf + HEADER_LEN, len))
|
||||
return 0; // we want to be called again ASAP because we still have more work to do
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we had packets available this time, so assume we might have them next time also
|
||||
lastRxMsec = now;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +85,7 @@ void StreamAPI::writeStream()
|
||||
void StreamAPI::emitTxBuffer(size_t len)
|
||||
{
|
||||
if (len != 0) {
|
||||
DEBUG_MSG("emit tx %d\n", len);
|
||||
// DEBUG_MSG("emit tx %d\n", len);
|
||||
txBuf[0] = START1;
|
||||
txBuf[1] = START2;
|
||||
txBuf[2] = (len >> 8) & 0xff;
|
||||
@@ -93,6 +107,6 @@ void StreamAPI::emitRebooted()
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
|
||||
fromRadioScratch.rebooted = true;
|
||||
|
||||
DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "PhoneAPI.h"
|
||||
#include "Stream.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
// A To/FromRadio packet + our 32 bit header
|
||||
#define MAX_STREAM_BUF_SIZE (MAX_TO_FROM_RADIO_SIZE + sizeof(uint32_t))
|
||||
@@ -27,7 +28,7 @@ valid utf8 encoding. This makes it a bit easier to start a device outputting reg
|
||||
after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding.
|
||||
|
||||
*/
|
||||
class StreamAPI : public PhoneAPI
|
||||
class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
||||
{
|
||||
/**
|
||||
* The stream we read/write from
|
||||
@@ -37,21 +38,23 @@ class StreamAPI : public PhoneAPI
|
||||
uint8_t rxBuf[MAX_STREAM_BUF_SIZE];
|
||||
size_t rxPtr = 0;
|
||||
|
||||
/// time of last rx, used, to slow down our polling if we haven't heard from anyone
|
||||
uint32_t lastRxMsec = 0;
|
||||
|
||||
public:
|
||||
StreamAPI(Stream *_stream) : stream(_stream) {}
|
||||
StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {}
|
||||
|
||||
/**
|
||||
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
|
||||
* phone.
|
||||
* FIXME, to support better power behavior instead move to a thread and block on serial reads.
|
||||
*/
|
||||
void loop();
|
||||
virtual int32_t runOnce();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Read any rx chars from the link and call handleToRadio
|
||||
*/
|
||||
void readStream();
|
||||
int32_t readStream();
|
||||
|
||||
/**
|
||||
* call getFromRadio() and deliver encapsulated packets to the Stream
|
||||
@@ -63,7 +66,7 @@ class StreamAPI : public PhoneAPI
|
||||
* Send a FromRadio.rebooted = true packet to the phone
|
||||
*/
|
||||
void emitRebooted();
|
||||
|
||||
|
||||
/**
|
||||
* Send the current txBuffer over our stream
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,7 @@ typedef struct _AdminMessage {
|
||||
bool confirm_set_channel;
|
||||
bool confirm_set_radio;
|
||||
bool exit_simulator;
|
||||
int32_t reboot_seconds;
|
||||
};
|
||||
} AdminMessage;
|
||||
|
||||
@@ -49,6 +50,7 @@ extern "C" {
|
||||
#define AdminMessage_confirm_set_channel_tag 32
|
||||
#define AdminMessage_confirm_set_radio_tag 33
|
||||
#define AdminMessage_exit_simulator_tag 34
|
||||
#define AdminMessage_reboot_seconds_tag 35
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define AdminMessage_FIELDLIST(X, a) \
|
||||
@@ -61,7 +63,8 @@ X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_requ
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) \
|
||||
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_channel), 32) \
|
||||
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \
|
||||
X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34)
|
||||
X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \
|
||||
X(a, STATIC, ONEOF, INT32, (variant,reboot_seconds,reboot_seconds), 35)
|
||||
#define AdminMessage_CALLBACK NULL
|
||||
#define AdminMessage_DEFAULT NULL
|
||||
#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig
|
||||
@@ -76,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 351
|
||||
#define AdminMessage_size 360
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -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 4920
|
||||
#define DeviceState_size 5118
|
||||
#define ChannelFile_size 832
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -110,6 +110,7 @@ typedef struct _MyNodeInfo {
|
||||
CriticalErrorCode error_code;
|
||||
uint32_t error_address;
|
||||
uint32_t error_count;
|
||||
uint32_t reboot_count;
|
||||
uint32_t message_timeout_msec;
|
||||
uint32_t min_app_version;
|
||||
uint32_t max_channels;
|
||||
@@ -161,6 +162,7 @@ typedef struct _NodeInfo {
|
||||
User user;
|
||||
bool has_position;
|
||||
Position position;
|
||||
uint32_t last_heard;
|
||||
float snr;
|
||||
} NodeInfo;
|
||||
|
||||
@@ -191,6 +193,7 @@ typedef struct _ToRadio {
|
||||
union {
|
||||
MeshPacket packet;
|
||||
uint32_t want_config_id;
|
||||
bool disconnect;
|
||||
};
|
||||
} ToRadio;
|
||||
|
||||
@@ -232,8 +235,8 @@ extern "C" {
|
||||
#define Routing_init_default {0, {RouteDiscovery_init_default}}
|
||||
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
||||
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
|
||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0}
|
||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
|
||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0}
|
||||
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
||||
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
|
||||
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
||||
@@ -243,8 +246,8 @@ extern "C" {
|
||||
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
|
||||
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
|
||||
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
|
||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0}
|
||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
|
||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0}
|
||||
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
|
||||
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
||||
@@ -269,6 +272,7 @@ extern "C" {
|
||||
#define MyNodeInfo_error_code_tag 7
|
||||
#define MyNodeInfo_error_address_tag 8
|
||||
#define MyNodeInfo_error_count_tag 9
|
||||
#define MyNodeInfo_reboot_count_tag 10
|
||||
#define MyNodeInfo_message_timeout_msec_tag 13
|
||||
#define MyNodeInfo_min_app_version_tag 14
|
||||
#define MyNodeInfo_max_channels_tag 15
|
||||
@@ -298,6 +302,7 @@ extern "C" {
|
||||
#define NodeInfo_num_tag 1
|
||||
#define NodeInfo_user_tag 2
|
||||
#define NodeInfo_position_tag 3
|
||||
#define NodeInfo_last_heard_tag 4
|
||||
#define NodeInfo_snr_tag 7
|
||||
#define Routing_route_request_tag 1
|
||||
#define Routing_route_reply_tag 2
|
||||
@@ -311,6 +316,7 @@ extern "C" {
|
||||
#define FromRadio_packet_tag 11
|
||||
#define ToRadio_packet_tag 2
|
||||
#define ToRadio_want_config_id_tag 100
|
||||
#define ToRadio_disconnect_tag 104
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define Position_FIELDLIST(X, a) \
|
||||
@@ -376,6 +382,7 @@ X(a, STATIC, SINGULAR, INT32, rx_rssi, 13)
|
||||
X(a, STATIC, SINGULAR, UINT32, num, 1) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, last_heard, 4) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, snr, 7)
|
||||
#define NodeInfo_CALLBACK NULL
|
||||
#define NodeInfo_DEFAULT NULL
|
||||
@@ -392,6 +399,7 @@ X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \
|
||||
X(a, STATIC, SINGULAR, UENUM, error_code, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error_address, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error_count, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, reboot_count, 10) \
|
||||
X(a, STATIC, SINGULAR, UINT32, message_timeout_msec, 13) \
|
||||
X(a, STATIC, SINGULAR, UINT32, min_app_version, 14) \
|
||||
X(a, STATIC, SINGULAR, UINT32, max_channels, 15)
|
||||
@@ -423,7 +431,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 11)
|
||||
|
||||
#define ToRadio_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100)
|
||||
X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payloadVariant,disconnect,disconnect), 104)
|
||||
#define ToRadio_CALLBACK NULL
|
||||
#define ToRadio_DEFAULT NULL
|
||||
#define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket
|
||||
@@ -460,8 +469,8 @@ extern const pb_msgdesc_t ToRadio_msg;
|
||||
#define Routing_size 42
|
||||
#define Data_size 260
|
||||
#define MeshPacket_size 309
|
||||
#define NodeInfo_size 126
|
||||
#define MyNodeInfo_size 89
|
||||
#define NodeInfo_size 131
|
||||
#define MyNodeInfo_size 95
|
||||
#define LogRecord_size 81
|
||||
#define FromRadio_size 318
|
||||
#define ToRadio_size 312
|
||||
|
||||
@@ -85,6 +85,8 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
bool is_router;
|
||||
bool is_low_power;
|
||||
bool fixed_position;
|
||||
bool serial_disabled;
|
||||
float frequency_offset;
|
||||
bool factory_reset;
|
||||
bool debug_log_enabled;
|
||||
pb_size_t ignore_incoming_count;
|
||||
@@ -150,9 +152,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, _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, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 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, _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, _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, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 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, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
||||
@@ -177,6 +179,8 @@ extern "C" {
|
||||
#define RadioConfig_UserPreferences_is_router_tag 37
|
||||
#define RadioConfig_UserPreferences_is_low_power_tag 38
|
||||
#define RadioConfig_UserPreferences_fixed_position_tag 39
|
||||
#define RadioConfig_UserPreferences_serial_disabled_tag 40
|
||||
#define RadioConfig_UserPreferences_frequency_offset_tag 41
|
||||
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
||||
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
|
||||
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
|
||||
@@ -237,6 +241,8 @@ X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
|
||||
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
|
||||
X(a, STATIC, SINGULAR, BOOL, serial_disabled, 40) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, frequency_offset, 41) \
|
||||
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) \
|
||||
@@ -276,8 +282,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 348
|
||||
#define RadioConfig_UserPreferences_size 345
|
||||
#define RadioConfig_size 357
|
||||
#define RadioConfig_UserPreferences_size 354
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "airtime.h"
|
||||
#include "main.h"
|
||||
#include "mesh/http/ContentHelper.h"
|
||||
@@ -11,7 +12,6 @@
|
||||
#include <HTTPMultipartBodyParser.hpp>
|
||||
#include <HTTPURLEncodedBodyParser.hpp>
|
||||
#include <SPIFFS.h>
|
||||
#include "RadioLibInterface.h"
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
@@ -77,7 +77,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
ResourceNode *nodeAPIv1ToRadio = new ResourceNode("/api/v1/toradio", "PUT", &handleAPIv1ToRadio);
|
||||
ResourceNode *nodeAPIv1FromRadio = new ResourceNode("/api/v1/fromradio", "GET", &handleAPIv1FromRadio);
|
||||
|
||||
ResourceNode *nodeHotspot = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot);
|
||||
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);
|
||||
@@ -96,7 +97,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
secureServer->registerNode(nodeAPIv1ToRadioOptions);
|
||||
secureServer->registerNode(nodeAPIv1ToRadio);
|
||||
secureServer->registerNode(nodeAPIv1FromRadio);
|
||||
secureServer->registerNode(nodeHotspot);
|
||||
secureServer->registerNode(nodeHotspotApple);
|
||||
secureServer->registerNode(nodeHotspotAndroid);
|
||||
secureServer->registerNode(nodeFavicon);
|
||||
secureServer->registerNode(nodeRoot);
|
||||
secureServer->registerNode(nodeStaticBrowse);
|
||||
@@ -117,7 +119,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
|
||||
insecureServer->registerNode(nodeAPIv1ToRadioOptions);
|
||||
insecureServer->registerNode(nodeAPIv1ToRadio);
|
||||
insecureServer->registerNode(nodeAPIv1FromRadio);
|
||||
insecureServer->registerNode(nodeHotspot);
|
||||
insecureServer->registerNode(nodeHotspotApple);
|
||||
insecureServer->registerNode(nodeHotspotAndroid);
|
||||
insecureServer->registerNode(nodeFavicon);
|
||||
insecureServer->registerNode(nodeRoot);
|
||||
insecureServer->registerNode(nodeStaticBrowse);
|
||||
@@ -931,6 +934,10 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging()));
|
||||
res->println("},");
|
||||
|
||||
res->println("\"device\": {");
|
||||
res->printf("\"reboot_counter\": %d\n", myNodeInfo.reboot_count);
|
||||
res->println("},");
|
||||
|
||||
res->println("\"radio\": {");
|
||||
res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq());
|
||||
res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum());
|
||||
@@ -938,8 +945,6 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
res->println("},");
|
||||
|
||||
|
||||
|
||||
res->println("\"status\": \"ok\"");
|
||||
res->println("}");
|
||||
}
|
||||
|
||||
@@ -40,18 +40,20 @@ void WiFiServerAPI::onConnectionChanged(bool connected)
|
||||
}
|
||||
|
||||
/// override close to also shutdown the TCP link
|
||||
void WiFiServerAPI::close() {
|
||||
void WiFiServerAPI::close()
|
||||
{
|
||||
client.stop(); // drop tcp connection
|
||||
StreamAPI::close();
|
||||
}
|
||||
|
||||
bool WiFiServerAPI::loop()
|
||||
int32_t WiFiServerAPI::runOnce()
|
||||
{
|
||||
if (client.connected()) {
|
||||
StreamAPI::loop();
|
||||
return true;
|
||||
return StreamAPI::runOnce();
|
||||
} else {
|
||||
return false;
|
||||
DEBUG_MSG("Client dropped connection, suspending API service\n");
|
||||
enabled = false; // we no longer need to run
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,18 +80,5 @@ int32_t WiFiServerPort::runOnce()
|
||||
openAPI = new WiFiServerAPI(client);
|
||||
}
|
||||
|
||||
if (openAPI) {
|
||||
// Allow idle processing so the API can read from its incoming stream
|
||||
if(!openAPI->loop()) {
|
||||
// If our API link was up, shut it down
|
||||
|
||||
DEBUG_MSG("Client dropped connection, closing API client\n");
|
||||
// Note: we can't call delete here because this object includes other state
|
||||
// besides the stream API. Instead kill it later when we start a new instance
|
||||
delete openAPI;
|
||||
openAPI = NULL;
|
||||
}
|
||||
return 0; // run fast while our API server is running
|
||||
} else
|
||||
return 100; // only check occasionally for incoming connections
|
||||
return 100; // only check occasionally for incoming connections
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "StreamAPI.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include <WiFi.h>
|
||||
|
||||
/**
|
||||
@@ -18,15 +17,14 @@ class WiFiServerAPI : public StreamAPI
|
||||
|
||||
virtual ~WiFiServerAPI();
|
||||
|
||||
/// @return true if we want to keep running, or false if we are ready to be destroyed
|
||||
virtual bool loop(); // Check for dropped client connections
|
||||
|
||||
/// override close to also shutdown the TCP link
|
||||
virtual void close();
|
||||
|
||||
protected:
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
|
||||
virtual int32_t runOnce(); // Check for dropped client connections
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -487,7 +487,6 @@ void reinitBluetooth()
|
||||
DEBUG_MSG("Starting bluetooth\n");
|
||||
if (isFirstTime) {
|
||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||
bluetoothPhoneAPI->init();
|
||||
}
|
||||
|
||||
// FIXME - if waking from light sleep, only esp_nimble_hci_init?
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include "BluetoothCommon.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <bluefruit.h>
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include "mesh/PhoneAPI.h"
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include <bluefruit.h>
|
||||
|
||||
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
|
||||
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
|
||||
@@ -155,7 +155,6 @@ void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt
|
||||
void setupMeshService(void)
|
||||
{
|
||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||
bluetoothPhoneAPI->init();
|
||||
|
||||
meshBleService.begin();
|
||||
|
||||
|
||||
@@ -77,6 +77,13 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag
|
||||
handleGetRadio(mp);
|
||||
break;
|
||||
|
||||
case AdminMessage_reboot_seconds_tag: {
|
||||
int32_t s = r->reboot_seconds;
|
||||
DEBUG_MSG("Rebooting in %d seconds\n", s);
|
||||
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef PORTDUINO
|
||||
case AdminMessage_exit_simulator_tag:
|
||||
DEBUG_MSG("Exiting simulator\n");
|
||||
|
||||
10
src/plugins/PluginDev.h
Normal file
10
src/plugins/PluginDev.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* To developers:
|
||||
* Use this to enable / disable features in your plugin that you don't want to risk checking into GitHub.
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable development more for StoreForwardPlugin
|
||||
bool StoreForward_Dev = false;
|
||||
@@ -10,10 +10,8 @@ PositionPlugin *positionPlugin;
|
||||
PositionPlugin::PositionPlugin()
|
||||
: ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin")
|
||||
{
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(60 *
|
||||
1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
|
||||
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
|
||||
}
|
||||
|
||||
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position *pptr)
|
||||
|
||||
@@ -255,7 +255,9 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fileToWrite.println("time,from,sender name,sender lat,sender long,rx lat,rx long,rx snr,distance,payload")) {
|
||||
// Print the CSV header
|
||||
if (fileToWrite.println(
|
||||
"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");
|
||||
@@ -296,7 +298,9 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long
|
||||
fileToAppend.printf("%f,", gpsStatus->getLatitude() * 1e-7); // RX Lat
|
||||
fileToAppend.printf("%f,", gpsStatus->getLongitude() * 1e-7); // RX Long
|
||||
fileToAppend.printf("%f,", mp.rx_snr); // RX SNR
|
||||
fileToAppend.printf("%d,", gpsStatus->getAltitude()); // RX Altitude
|
||||
|
||||
fileToAppend.printf("%f,", mp.rx_snr); // RX SNR
|
||||
|
||||
if (n->position.latitude_i && n->position.longitude_i && gpsStatus->getLatitude() && gpsStatus->getLongitude()) {
|
||||
float distance = latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7,
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/PluginDev.h"
|
||||
#include <Arduino.h>
|
||||
#include <map>
|
||||
|
||||
#define STOREFORWARD_MAX_PACKETS 0
|
||||
#define STOREFORWARD_SEND_HISTORY_SHORT 600
|
||||
#define STOREFORWARD_SEND_HISTORY_PERIOD 10 * 60
|
||||
#define STOREFORWARD_SEND_HISTORY_MAX 0
|
||||
|
||||
StoreForwardPlugin *storeForwardPlugin;
|
||||
|
||||
@@ -22,9 +24,8 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
|
||||
if (radioConfig.preferences.is_router) {
|
||||
// Maybe some cleanup functions?
|
||||
this->sawNodeReport();
|
||||
this->historyReport();
|
||||
return (10 * 1000);
|
||||
return (60 * 1000);
|
||||
} else {
|
||||
/*
|
||||
* If the plugin is turned on and is_router is not enabled, then we'll send a heartbeat every
|
||||
@@ -64,14 +65,12 @@ void StoreForwardPlugin::populatePSRAM()
|
||||
DEBUG_MSG(" Total PSRAM: %d\n", ESP.getPsramSize());
|
||||
DEBUG_MSG(" Free PSRAM: %d\n", ESP.getFreePsram());
|
||||
|
||||
// PacketHistoryStruct *packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS,
|
||||
// sizeof(PacketHistoryStruct));
|
||||
|
||||
// Use a maximum of half the available PSRAM unless otherwise specified.
|
||||
uint32_t numberOfPackets =
|
||||
STOREFORWARD_MAX_PACKETS ? STOREFORWARD_MAX_PACKETS : ((ESP.getPsramSize() / 2) / sizeof(PacketHistoryStruct));
|
||||
|
||||
this->packetHistory = (PacketHistoryStruct *)ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct));
|
||||
// this->packetHistory = (PacketHistoryStruct *)ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct));
|
||||
this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct)));
|
||||
DEBUG_MSG("After PSRAM initilization:\n");
|
||||
|
||||
DEBUG_MSG(" Total heap: %d\n", ESP.getHeapSize());
|
||||
@@ -83,41 +82,17 @@ void StoreForwardPlugin::populatePSRAM()
|
||||
}
|
||||
|
||||
// We saw a node.
|
||||
uint32_t StoreForwardPlugin::sawNode(uint32_t node)
|
||||
void StoreForwardPlugin::sawNode(uint32_t whoWeSaw, uint32_t sawSecAgo)
|
||||
{
|
||||
if (radioConfig.preferences.is_router) {
|
||||
|
||||
/*
|
||||
TODO: Move receivedRecord into the PSRAM
|
||||
|
||||
TODO: Gracefully handle the case where we run out of records.
|
||||
Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back.
|
||||
|
||||
TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?).
|
||||
*/
|
||||
// DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
// p->want_ack, p->hop_limit);
|
||||
DEBUG_MSG("looking for node - from-0x%08x\n", node);
|
||||
for (int i = 0; i < 50; i++) {
|
||||
// DEBUG_MSG("Iterating through the seen nodes - %u %u %u\n", i, receivedRecord[i][0], receivedRecord[i][1]);
|
||||
// First time seeing that node.
|
||||
if (receivedRecord[i][0] == 0) {
|
||||
// DEBUG_MSG("New node! Woohoo! Win!\n");
|
||||
receivedRecord[i][0] = node;
|
||||
receivedRecord[i][1] = millis();
|
||||
|
||||
return receivedRecord[i][1];
|
||||
}
|
||||
|
||||
// We've seen this node before.
|
||||
if (receivedRecord[i][0] == node) {
|
||||
// DEBUG_MSG("We've seen this node before\n");
|
||||
uint32_t lastSaw = receivedRecord[i][1];
|
||||
receivedRecord[i][1] = millis();
|
||||
return lastSaw;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StoreForwardPlugin::historyReport()
|
||||
@@ -132,8 +107,15 @@ void StoreForwardPlugin::historyReport()
|
||||
}
|
||||
DEBUG_MSG("StoreForwardPlugin::historyReport runtime - %u ms\n", millis() - startTimer);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void StoreForwardPlugin::historySend(uint32_t msAgo, uint32_t to)
|
||||
{
|
||||
// Send "Welcome back"
|
||||
this->sendPayloadWelcome(to, false);
|
||||
|
||||
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);
|
||||
@@ -159,27 +141,6 @@ void StoreForwardPlugin::historyAdd(const MeshPacket *mp)
|
||||
this->packetHistoryCurrent++;
|
||||
}
|
||||
|
||||
// We saw a node.
|
||||
void StoreForwardPlugin::sawNodeReport()
|
||||
{
|
||||
|
||||
/*
|
||||
TODO: Move receivedRecord into the PSRAM
|
||||
|
||||
TODO: Gracefully handle the case where we run out of records.
|
||||
Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back.
|
||||
|
||||
TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?).
|
||||
*/
|
||||
|
||||
DEBUG_MSG("Iterating through the seen nodes in receivedRecord...\n");
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (receivedRecord[i][1]) {
|
||||
DEBUG_MSG("... record-%u from-0x%08x secAgo-%u\n", i, receivedRecord[i][0], (millis() - receivedRecord[i][1]) / 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MeshPacket *StoreForwardPlugin::allocReply()
|
||||
{
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
@@ -194,8 +155,7 @@ void StoreForwardPlugin::sendPayload(NodeNum dest, bool wantReplies)
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = true;
|
||||
/*
|
||||
*/
|
||||
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "1");
|
||||
|
||||
@@ -205,60 +165,50 @@ void StoreForwardPlugin::sendPayload(NodeNum dest, bool wantReplies)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
p->want_ack = true;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool StoreForwardPlugin::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
// DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n");
|
||||
// DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
// p->want_ack, p->hop_limit);
|
||||
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);
|
||||
// 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_UNKNOWN_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_UNKNOWN_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
|
||||
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n");
|
||||
|
||||
storeForwardPlugin->historyAdd(&mp);
|
||||
|
||||
} else if (mp.decoded.portnum == PortNum_REMOTE_HARDWARE_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_REMOTE_HARDWARE_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_POSITION_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_POSITION_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_NODEINFO_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_NODEINFO_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_ROUTING_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_ROUTING_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_ADMIN_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_ADMIN_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_REPLY_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_REPLY_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_IP_TUNNEL_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_IP_TUNNEL_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_SERIAL_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_SERIAL_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_STORE_FORWARD_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_RANGE_TEST_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_RANGE_TEST_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_PRIVATE_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_PRIVATE_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_RANGE_TEST_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_RANGE_TEST_APP\n");
|
||||
} else if (mp.decoded.portnum == PortNum_ATAK_FORWARDER) {
|
||||
DEBUG_MSG("Packet came from - PortNum_ATAK_FORWARDER\n");
|
||||
} else {
|
||||
DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum);
|
||||
}
|
||||
|
||||
if ((millis() - sawTime) > STOREFORWARD_SEND_HISTORY_SHORT) {
|
||||
// Node has been away for a while.
|
||||
storeForwardPlugin->historySend(sawTime, mp.from);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -276,14 +226,18 @@ StoreForwardPlugin::StoreForwardPlugin()
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
||||
isPromiscuous = true; // Brown chicken brown cow
|
||||
|
||||
/*
|
||||
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;
|
||||
*/
|
||||
|
||||
if (StoreForward_Dev) {
|
||||
radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
radioConfig.preferences.is_router = 1;
|
||||
}
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
// Router
|
||||
|
||||
@@ -29,8 +29,7 @@ class StoreForwardPlugin : public SinglePortPlugin, private concurrency::OSThrea
|
||||
Update our local reference of when we last saw that node.
|
||||
@return 0 if we have never seen that node before otherwise return the last time we saw the node.
|
||||
*/
|
||||
uint32_t sawNode(uint32_t);
|
||||
void sawNodeReport();
|
||||
void sawNode(uint32_t whoWeSaw, uint32_t sawSecAgo);
|
||||
void historyAdd(const MeshPacket *mp);
|
||||
void historyReport();
|
||||
void historySend(uint32_t msAgo, uint32_t to);
|
||||
@@ -40,6 +39,7 @@ class StoreForwardPlugin : public SinglePortPlugin, private concurrency::OSThrea
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
void sendPayloadWelcome(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
virtual MeshPacket *allocReply();
|
||||
virtual bool wantPortnum(PortNum p) { return true; };
|
||||
|
||||
@@ -80,4 +80,3 @@ class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
|
||||
extern StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,76 +1,61 @@
|
||||
#include "CryptoEngine.h"
|
||||
#include "target_specific.h"
|
||||
#include "PortduinoGPIO.h"
|
||||
#include "mesh/RF95Interface.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
|
||||
#include <Utility.h>
|
||||
#include <assert.h>
|
||||
|
||||
// FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class
|
||||
|
||||
uint32_t hwId; // fixme move into portduino
|
||||
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
if (!hwId) {
|
||||
notImplemented("getMacAddr");
|
||||
hwId = random();
|
||||
}
|
||||
|
||||
dmac[0] = 0x80;
|
||||
dmac[1] = 0;
|
||||
dmac[2] = 0;
|
||||
dmac[3] = hwId >> 16;
|
||||
dmac[4] = hwId >> 8;
|
||||
dmac[5] = hwId & 0xff;
|
||||
}
|
||||
// FIXME - move setBluetoothEnable into a HALPlatform class
|
||||
|
||||
void setBluetoothEnable(bool on)
|
||||
{
|
||||
// not needed
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint64_t msecs) {
|
||||
void cpuDeepSleep(uint64_t msecs)
|
||||
{
|
||||
notImplemented("cpuDeepSleep");
|
||||
}
|
||||
|
||||
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
|
||||
|
||||
/** Dear pinetab hardware geeks!
|
||||
*
|
||||
*
|
||||
* The current pinetab lora module has a slight bug. The ch341 part only provides ISR assertions on edges.
|
||||
* This makes sense because USB interrupts happen through fast/repeated special irq urbs that are constantly
|
||||
* chattering on the USB bus.
|
||||
*
|
||||
*
|
||||
* But this isn't sufficient for level triggered ISR sources like the sx127x radios. The common way that seems to
|
||||
* be addressed by cs341 users is to **always** connect the INT# (pin 26 on the ch341f) signal to one of the GPIO signals
|
||||
* on the part. I'd recommend connecting that LORA_DIO0/INT# line to pin 19 (data 4) on the pinetab board. This would
|
||||
* provide an efficent mechanism so that the (kernel) code in the cs341 driver that I've slightly hacked up to see the
|
||||
* current state of LORA_DIO0. Without that access, I can't know if the interrupt is still pending - which would create
|
||||
* race conditions in packet handling.
|
||||
*
|
||||
* race conditions in packet handling.
|
||||
*
|
||||
* My workaround is to poll the status register internally to the sx127x. Which is expensive because it involves a number of
|
||||
* i2c transactions and many trips back and forth between kernel and my userspace app. I think shipping the current version
|
||||
* of the pinetab lora device would be fine because I can poll slowly (because lora is slow). But if you ever have cause to
|
||||
* rev this board. I highly encourage this small change.
|
||||
*
|
||||
*
|
||||
* Btw - your little "USB lora dongle" is really neat. I encourage you to sell it, because even non pinetab customers could
|
||||
* use it to easily add lora to rasberry pi, desktop pcs etc...
|
||||
*
|
||||
*
|
||||
* Porduino helper class to do this i2c based polling:
|
||||
*/
|
||||
class R595PolledIrqPin : public GPIOPin {
|
||||
public:
|
||||
class R595PolledIrqPin : public GPIOPin
|
||||
{
|
||||
public:
|
||||
R595PolledIrqPin() : GPIOPin(LORA_DIO0, "LORA_DIO0") {}
|
||||
|
||||
/// Read the low level hardware for this pin
|
||||
virtual PinStatus readPinHardware()
|
||||
{
|
||||
if(isrPinStatus < 0)
|
||||
if (isrPinStatus < 0)
|
||||
return LOW; // No interrupt handler attached, don't bother polling i2c right now
|
||||
else {
|
||||
extern RadioInterface *rIf; // FIXME, temporary hack until we know if we need to keep this
|
||||
extern RadioInterface *rIf; // FIXME, temporary hack until we know if we need to keep this
|
||||
|
||||
assert(rIf);
|
||||
RF95Interface *rIf95 = static_cast<RF95Interface *>(rIf);
|
||||
@@ -81,17 +66,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
||||
* before running 'arduino' code.
|
||||
*/
|
||||
void portduinoSetup() {
|
||||
printf("Setting up Meshtastic on Porduino...\n");
|
||||
void portduinoSetup()
|
||||
{
|
||||
printf("Setting up Meshtastic on Porduino...\n");
|
||||
|
||||
// FIXME: disable while not testing with real hardware
|
||||
// gpioBind(new R595PolledIrqPin());
|
||||
// FIXME: disable while not testing with real hardware
|
||||
// gpioBind(new R595PolledIrqPin());
|
||||
|
||||
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
|
||||
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
|
||||
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
|
||||
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 1
|
||||
minor = 2
|
||||
build = 13
|
||||
build = 20
|
||||
|
||||
Reference in New Issue
Block a user