mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-06 18:08:00 +00:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0fbfccf43 | ||
|
|
51ccc3aa9e | ||
|
|
e35f137986 | ||
|
|
71c35304d6 | ||
|
|
c1733a4ac6 | ||
|
|
66a7e8eab9 | ||
|
|
a872231f8a | ||
|
|
52ec4d511c | ||
|
|
aa7fb86798 | ||
|
|
875eeb699c | ||
|
|
b239b4dc57 | ||
|
|
19db5ba421 | ||
|
|
e225af28dc | ||
|
|
eecf89a9c0 | ||
|
|
c9b1ee532d | ||
|
|
8c27baae84 | ||
|
|
8c225a3c65 | ||
|
|
7ff1f3a759 | ||
|
|
bbc8fc0269 | ||
|
|
9d81511153 | ||
|
|
16d63bd0ce | ||
|
|
f2b7ff2b79 | ||
|
|
bc8453283f | ||
|
|
2ff5046dcd | ||
|
|
917090856f | ||
|
|
b45d633a34 | ||
|
|
fdfe62edf0 | ||
|
|
b29bcbbd41 | ||
|
|
8e8170b667 | ||
|
|
2fa38c7dc4 | ||
|
|
ca8a0ca8d2 | ||
|
|
58bb7169a0 | ||
|
|
cb541d75a9 | ||
|
|
4ee01acb40 | ||
|
|
d678c48884 | ||
|
|
9f9f02fc6f | ||
|
|
abf135abce | ||
|
|
22af1b551a | ||
|
|
c696d226b2 | ||
|
|
9035a06b4a | ||
|
|
056940a4ad | ||
|
|
82db1f1db6 | ||
|
|
f46059ec4c | ||
|
|
0c71de4e59 | ||
|
|
0fa654e53a | ||
|
|
45c17659cc | ||
|
|
b901f8d9ae | ||
|
|
9c60a7966f | ||
|
|
6d66a53f8d | ||
|
|
324627482a | ||
|
|
0c6c189028 | ||
|
|
8a68ae0d04 | ||
|
|
5661e5dad6 | ||
|
|
e9affb50d2 | ||
|
|
c00173dbd2 | ||
|
|
e8c6fccd63 | ||
|
|
487b8c6e9e | ||
|
|
b2481d1450 | ||
|
|
242bcc8353 |
@@ -31,11 +31,75 @@ Channel zero starts at 903.08 MHz center frequency.
|
||||
|
||||
## Data-rates
|
||||
|
||||
Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices:
|
||||
### About
|
||||
|
||||
| Channel setting | Data-rate |
|
||||
|----------------------------|----------------------|
|
||||
| Short range (but fast) | 21.875 kbps |
|
||||
| Medium range (but fast) | 5.469 kbps |
|
||||
| Long range (but slower) | 0.275 kbps |
|
||||
| Very long range (but slow) | 0.183 kbps (default) |
|
||||
Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices.
|
||||
|
||||
Considerations:
|
||||
|
||||
* Spreading Factor - How much we "spread" our data over time.
|
||||
* * Each step up in Spreading Factor dobules the airtime to transmit.
|
||||
* * Each step up in Spreading Factor adds about 2.5db extra link budget.
|
||||
* Bandwidth - How big of a slice of the spectrum we use.
|
||||
* * Each doubling of the bandwidth is almost 3db less link budget.
|
||||
* * Bandwidths less than 31 may be unstable unless you have a high quality Crystal Ossilator.
|
||||
* Coding Rate - How much redundency we encode to resist noise.
|
||||
* * Increasing coding rate increases reliability while decrasing data-rate.
|
||||
* * 4/5 - 1.25x overhead
|
||||
* * 4/6 - 1.5x overhead
|
||||
* * 4/7 - 1.75x overhead
|
||||
* * 4/8 - 2x overhead
|
||||
|
||||
|
||||
### Pre-Defined
|
||||
|
||||
We have four predefined channels. These are the most common settings and have been proven to work well:
|
||||
|
||||
| Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | Link Budget |
|
||||
|:---------------------------|:-----------------|:---------------------|:-------------|:------------|:----------|:------------|
|
||||
| Short range (but fast) | Short Fast | 21.875 kbps | 7 / 128 | 4/5 | 125 | 134dB |
|
||||
| Medium range (but fast) | Medium | 5.469 kbps | 7 / 128 | 4/5 | 500 | 140dB |
|
||||
| Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | 153dB |
|
||||
| Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | 154dB |
|
||||
|
||||
The link budget used by these calculations assumes a transmit power of 17dBm and an antenna with 0dB gain. Adjust your link budget assumptions based on your actual devices.
|
||||
|
||||
### Custom Settings
|
||||
|
||||
You may want to select other channels for your usage. The other settings can be set by using the Python API.
|
||||
|
||||
> meshtastic --setchan spread_factor 10 --setchan coding_rate 8 --setchan bandwidth 125
|
||||
|
||||
After applying the settings, you will need to restart the device. After your device is restarted, it will generate a new crypto key and you will need to share the newly generated QR Code or URL to all your other devices.
|
||||
|
||||
Some example settings:
|
||||
|
||||
| Data-rate | SF / Symbols | Coding Rate | Bandwidth | Link Budget | Note |
|
||||
|:---------------------|:-------------|:------------|:----------|:------------|:-----|
|
||||
| 37.50 kbps | 6 / 64 | 4/5 | 500 | 129dB | Fastest possible speed |
|
||||
| 3.125 kbps | 8 / 256 | 4/5 | 125 | 143dB | |
|
||||
| 1.953 kbps | 8 / 256 | 4/8 | 125 | 143dB | |
|
||||
| 1.343 kbps | 11 / 2048 | 4/8 | 500 | 145dB | |
|
||||
| 1.099 kbps | 9 / 512 | 4/8 | 125 | 146dB | |
|
||||
| 0.814 kbps | 10 / 1024 | 4/6 | 125 | 149dB | |
|
||||
| 0.610 kbps | 10 / 1024 | 4/8 | 125 | 149dB | |
|
||||
| 0.488 kbps | 11 / 2048 | 4/6 | 125 | 152dB | |
|
||||
| 0.336 kbps | 11 / 2048 | 4/8 | 125 | 152dB | |
|
||||
| 0.073 kbps | 12 / 4096 | 4/5 | 31 | 160dB | Twice the range and/or coverage of "Long Slow", low resliance to noise |
|
||||
| 0.046 kbps | 12 / 4096 | 4/8 | 31 | 160dB | Twice the range and/or coverage of "Long Slow", high resliance to noise |
|
||||
|
||||
The link budget used by these calculations assumes a transmit power of 17dBm and an antenna with 0dB gain. Adjust your link budget assumptions based on your actual devices.
|
||||
|
||||
These channel settings may have not been tested. Use at your own discression. Share on https://meshtastic.discourse.group with your successes or failure.
|
||||
|
||||
## Cryptography
|
||||
|
||||
The preshared key used by the devices can be modified.
|
||||
|
||||
* 0 = No crypto
|
||||
* 1 = Default channel key
|
||||
* 2 - 10 = The default channel key, except with 1 through 9 added to the last byte
|
||||
|
||||
Use of cryptography can also be modified. To disable cryptography (maybe useful if you have HAM radio license):
|
||||
|
||||
> meshtastic --setchan psk 0
|
||||
|
||||
21
docs/software/plugins/StoreForwardPlugin.md
Normal file
21
docs/software/plugins/StoreForwardPlugin.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# About
|
||||
|
||||
This is a work in progress and is not yet available.
|
||||
|
||||
The Store Request Plugin is an implementation of a Store and Forward system to enable resilient messaging in the event that a client device is disconnected from the main network.
|
||||
|
||||
Because of the increased network traffic for this overhead, it's not adviced to use this if you are duty cycle limited for your airtime usage nor is it adviced to use this for SF12.
|
||||
|
||||
# Running notes
|
||||
|
||||
This will only work on nodes that are designated as a Router.
|
||||
|
||||
Initial Requirements:
|
||||
|
||||
* Must be installed on a router node.
|
||||
* * This is an artificial limitation, but is in place to enforce best practices.
|
||||
* * Router nodes are intended to be always online. If this plugin misses any messages, the reliability of the stored messages will be reduced
|
||||
* Esp32 Processor based device with external PSRAM. (tbeam v1.0 and tbeamv1.1, maybe others)
|
||||
|
||||
Initial Features
|
||||
*
|
||||
@@ -1,6 +0,0 @@
|
||||
# About
|
||||
|
||||
|
||||
|
||||
# Running notes
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
;default_envs = tbeam
|
||||
default_envs = tbeam
|
||||
;default_envs = tbeam0.7
|
||||
;default_envs = heltec
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = lora-relay-v1 # nrf board
|
||||
default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
|
||||
[common]
|
||||
; common is not currently used
|
||||
@@ -342,4 +342,4 @@ lib_deps =
|
||||
extends = esp32_base
|
||||
board = genieblocks_lora
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D GENIEBLOCKS
|
||||
${esp32_base.build_flags} -D GENIEBLOCKS
|
||||
2
proto
2
proto
Submodule proto updated: 106f4bfdeb...0cadaed395
@@ -9,6 +9,7 @@ enum class Cmd {
|
||||
SET_OFF,
|
||||
ON_PRESS,
|
||||
START_BLUETOOTH_PIN_SCREEN,
|
||||
START_FIRMWARE_UPDATE_SCREEN,
|
||||
STOP_BLUETOOTH_PIN_SCREEN,
|
||||
STOP_BOOT_SCREEN,
|
||||
PRINT,
|
||||
|
||||
@@ -309,6 +309,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
#elif defined(TLORA_V1_3)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tlora-v1-3"
|
||||
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 13 // per @eugene
|
||||
|
||||
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 15
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 36
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 35 // Not really used
|
||||
#define LORA_DIO2 34 // Not really used
|
||||
|
||||
#elif defined(TLORA_V2_1_16)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tlora-v2-1-1.6"
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "configuration.h"
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#include "NodeDB.h"
|
||||
#include "../graphics/Screen.h"
|
||||
#include "../main.h"
|
||||
|
||||
#include <CRC32.h>
|
||||
#include <Update.h>
|
||||
@@ -47,8 +49,9 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
|
||||
// void stopMeshBluetoothService();
|
||||
// stopMeshBluetoothService();
|
||||
|
||||
screen->startFirmwareUpdateScreen();
|
||||
if (RadioLibInterface::instance)
|
||||
RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are
|
||||
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are
|
||||
// writing flash - shut the radio off during updates
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,20 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
display->drawString(64 + x, 48 + y, buf);
|
||||
}
|
||||
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, y, "Updating");
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait...");
|
||||
|
||||
//display->setFont(FONT_LARGE);
|
||||
//display->drawString(64 + x, 26 + y, btPIN);
|
||||
}
|
||||
|
||||
|
||||
/// Draw the last text message we received
|
||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -201,7 +215,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
|
||||
// the max length of this buffer is much longer than we can possibly print
|
||||
static char tempBuf[96];
|
||||
assert(mp.decoded.which_payload == SubPacket_data_tag);
|
||||
assert(mp.decoded.which_payloadVariant == SubPacket_data_tag);
|
||||
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
|
||||
|
||||
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf);
|
||||
@@ -798,6 +812,9 @@ int32_t Screen::runOnce()
|
||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||
break;
|
||||
case Cmd::START_FIRMWARE_UPDATE_SCREEN:
|
||||
handleStartFirmwareUpdateScreen();
|
||||
break;
|
||||
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
|
||||
case Cmd::STOP_BOOT_SCREEN:
|
||||
setFrames();
|
||||
@@ -928,6 +945,18 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
void Screen::handleStartFirmwareUpdateScreen()
|
||||
{
|
||||
DEBUG_MSG("showing firmware screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback btFrames[] = {drawFrameFirmware};
|
||||
|
||||
ui.disableAllIndicators();
|
||||
ui.setFrames(btFrames, 1);
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
void Screen::blink()
|
||||
{
|
||||
setFastFramerate();
|
||||
|
||||
@@ -128,6 +128,14 @@ class Screen : public concurrency::OSThread
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
void startFirmwareUpdateScreen()
|
||||
{
|
||||
ScreenCmd cmd;
|
||||
cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN;
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
|
||||
/// Stops showing the bluetooth PIN screen.
|
||||
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
|
||||
|
||||
@@ -233,6 +241,7 @@ class Screen : public concurrency::OSThread
|
||||
void handleOnPress();
|
||||
void handleStartBluetoothPinScreen(uint32_t pin);
|
||||
void handlePrint(const char *text);
|
||||
void handleStartFirmwareUpdateScreen();
|
||||
|
||||
/// Rebuilds our list of frames (screens) to default ones.
|
||||
void setFrames();
|
||||
|
||||
@@ -72,7 +72,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
|
||||
addRoute(p->from, p->from, 0); // We are adjacent with zero hops
|
||||
}
|
||||
|
||||
switch (p->decoded.which_payload) {
|
||||
switch (p->decoded.which_payloadVariant) {
|
||||
case SubPacket_route_request_tag:
|
||||
// Handle route discovery packets (will be a broadcast message)
|
||||
// FIXME - always start request with the senders nodenum
|
||||
@@ -139,7 +139,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
|
||||
|
||||
// handle naks - convert them to route error packets
|
||||
// All naks are generated locally, because we failed resending the packet too many times
|
||||
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
|
||||
PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
|
||||
if (nakId) {
|
||||
auto pending = findPendingPacket(p->to, nakId);
|
||||
if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore
|
||||
|
||||
91
src/mesh/MeshPacketQueue.cpp
Normal file
91
src/mesh/MeshPacketQueue.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "MeshPacketQueue.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/// @return the priority of the specified packet
|
||||
inline uint32_t getPriority(MeshPacket *p)
|
||||
{
|
||||
auto pri = p->priority;
|
||||
return pri;
|
||||
}
|
||||
|
||||
/// @return "true" if "p1" is ordered before "p2"
|
||||
bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2)
|
||||
{
|
||||
assert(p1 && p2);
|
||||
auto p1p = getPriority(p1), p2p = getPriority(p2);
|
||||
|
||||
// If priorities differ, use that
|
||||
// for equal priorities, order by id (older packets have higher priority - this will briefly be wrong when IDs roll over but
|
||||
// no big deal)
|
||||
return (p1p != p2p) ? (p1p < p2p) // prefer bigger priorities
|
||||
: (p1->id >= p2->id); // prefer smaller packet ids
|
||||
}
|
||||
|
||||
MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {}
|
||||
|
||||
/** Some clients might not properly set priority, therefore we fix it here.
|
||||
*/
|
||||
void fixPriority(MeshPacket *p)
|
||||
{
|
||||
// We might receive acks from other nodes (and since generated remotely, they won't have priority assigned. Check for that
|
||||
// and fix it
|
||||
if (p->priority == MeshPacket_Priority_UNSET) {
|
||||
// if acks give high priority
|
||||
// if a reliable message give a bit higher default priority
|
||||
p->priority = p->decoded.which_ackVariant ? MeshPacket_Priority_ACK :
|
||||
(p->want_ack ? MeshPacket_Priority_RELIABLE : MeshPacket_Priority_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
/** enqueue a packet, return false if full */
|
||||
bool MeshPacketQueue::enqueue(MeshPacket *p)
|
||||
{
|
||||
|
||||
fixPriority(p);
|
||||
|
||||
// fixme if there is something lower priority in the queue that can be deleted to make space, delete that instead
|
||||
if (size() >= maxLen)
|
||||
return false;
|
||||
else {
|
||||
push(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
MeshPacket *MeshPacketQueue::dequeue()
|
||||
{
|
||||
if (empty())
|
||||
return NULL;
|
||||
else {
|
||||
auto p = top();
|
||||
pop(); // remove the first item
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
// this is kinda yucky, but I'm not sure if all arduino c++ compilers support closuers. And we only have one
|
||||
// thread that can run at a time - so safe
|
||||
static NodeNum findFrom;
|
||||
static PacketId findId;
|
||||
|
||||
static bool isMyPacket(MeshPacket *p)
|
||||
{
|
||||
return p->id == findId && p->from == findFrom;
|
||||
}
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
|
||||
MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
|
||||
{
|
||||
findFrom = from;
|
||||
findId = id;
|
||||
auto it = std::find_if(this->c.begin(), this->c.end(), isMyPacket);
|
||||
if (it != this->c.end()) {
|
||||
auto p = *it;
|
||||
this->c.erase(it);
|
||||
std::make_heap(this->c.begin(), this->c.end(), this->comp);
|
||||
return p;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
33
src/mesh/MeshPacketQueue.h
Normal file
33
src/mesh/MeshPacketQueue.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "MeshTypes.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <queue>
|
||||
|
||||
// this is an strucure which implements the
|
||||
// operator overloading
|
||||
struct CompareMeshPacket {
|
||||
bool operator()(MeshPacket *p1, MeshPacket *p2);
|
||||
};
|
||||
|
||||
/**
|
||||
* A priority queue of packets.
|
||||
*
|
||||
*/
|
||||
class MeshPacketQueue : public std::priority_queue<MeshPacket *, std::vector<MeshPacket *>, CompareMeshPacket>
|
||||
{
|
||||
size_t maxLen;
|
||||
public:
|
||||
MeshPacketQueue(size_t _maxLen);
|
||||
|
||||
/** enqueue a packet, return false if full */
|
||||
bool enqueue(MeshPacket *p);
|
||||
|
||||
// bool isEmpty();
|
||||
|
||||
MeshPacket *dequeue();
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
|
||||
MeshPacket *remove(NodeNum from, PacketId id);
|
||||
};
|
||||
@@ -51,22 +51,7 @@ MeshService service;
|
||||
|
||||
#include "Router.h"
|
||||
|
||||
static int32_t sendOwnerCb()
|
||||
{
|
||||
static uint32_t currentGeneration;
|
||||
|
||||
// If we changed channels, ask everyone else for their latest info
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
|
||||
assert(nodeInfoPlugin);
|
||||
nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
|
||||
|
||||
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
|
||||
}
|
||||
|
||||
static concurrency::Periodic *sendOwnerPeriod;
|
||||
|
||||
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
|
||||
{
|
||||
@@ -75,9 +60,6 @@ MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
|
||||
|
||||
void MeshService::init()
|
||||
{
|
||||
sendOwnerPeriod = new concurrency::Periodic("SendOwner", sendOwnerCb);
|
||||
sendOwnerPeriod->setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
|
||||
|
||||
// moved much earlier in boot (called from setup())
|
||||
// nodeDB.init();
|
||||
|
||||
@@ -169,22 +151,15 @@ void MeshService::handleToRadio(MeshPacket &p)
|
||||
}
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
|
||||
bool MeshService::cancelSending(PacketId id) {
|
||||
return router->cancelSending(nodeDB.getNodeNum(), id);
|
||||
}
|
||||
|
||||
void MeshService::sendToMesh(MeshPacket *p)
|
||||
{
|
||||
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||
|
||||
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
|
||||
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
|
||||
// devices can get time.
|
||||
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag &&
|
||||
p->decoded.position.time) {
|
||||
if (getRTCQuality() < RTCQualityGPS) {
|
||||
DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);
|
||||
p->decoded.position.time = 0;
|
||||
} else
|
||||
DEBUG_MSG("Providing time to mesh %u\n", p->decoded.position.time);
|
||||
}
|
||||
|
||||
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
|
||||
router->sendLocal(p);
|
||||
}
|
||||
@@ -216,7 +191,7 @@ 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 = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
|
||||
position.time = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
|
||||
|
||||
position.battery_level = powerStatus->getBatteryChargePercent();
|
||||
updateBatteryLevel(position.battery_level);
|
||||
@@ -239,7 +214,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
||||
else {
|
||||
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||
// the old position
|
||||
if(!radioConfig.preferences.fixed_position) {
|
||||
if(radioConfig.preferences.fixed_position) {
|
||||
DEBUG_MSG("WARNING: Using fixed position\n");
|
||||
} else {
|
||||
// throw away old position
|
||||
@@ -249,27 +224,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
|
||||
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.time, pos.latitude_i, pos.battery_level);
|
||||
|
||||
// Update our current position in the local DB
|
||||
nodeDB.updatePosition(nodeDB.getNodeNum(), pos);
|
||||
|
||||
// We limit our GPS broadcasts to a max rate
|
||||
static uint32_t lastGpsSend;
|
||||
uint32_t now = millis();
|
||||
if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) {
|
||||
lastGpsSend = now;
|
||||
|
||||
static uint32_t currentGeneration;
|
||||
|
||||
// If we changed channels, ask everyone else for their latest info
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies);
|
||||
assert(positionPlugin);
|
||||
positionPlugin->sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@ class MeshService
|
||||
/// cache
|
||||
void sendToMesh(MeshPacket *p);
|
||||
|
||||
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
|
||||
bool cancelSending(PacketId id);
|
||||
|
||||
/// Pull the latest power and time info into my nodeinfo
|
||||
NodeInfo *refreshMyNodeInfo();
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ typedef uint32_t PacketId; // A packet sequence number
|
||||
#define ERRNO_OK 0
|
||||
#define ERRNO_NO_INTERFACES 33
|
||||
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
|
||||
#define ERRNO_DISABLED 34 // the itnerface is disabled
|
||||
|
||||
/**
|
||||
* the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket.
|
||||
|
||||
@@ -265,16 +265,15 @@ void NodeDB::installDefaultDeviceState()
|
||||
|
||||
// Init our blank owner info to reasonable defaults
|
||||
getMacAddr(ourMacAddr);
|
||||
sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0], ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4],
|
||||
ourMacAddr[5]);
|
||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||
|
||||
// Set default owner name
|
||||
pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid
|
||||
// owner.short_name now
|
||||
pickNewNodeNum(); // based on macaddr now
|
||||
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
|
||||
sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff));
|
||||
|
||||
sprintf(owner.id, "!%08x", getNodeNum()); // Default node ID now based on nodenum
|
||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||
|
||||
// Restore region if possible
|
||||
if (oldRegionCode != RegionCode_Unset)
|
||||
radioConfig.preferences.region = oldRegionCode;
|
||||
@@ -526,7 +525,7 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p)
|
||||
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
||||
void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
{
|
||||
if (mp.which_payload == MeshPacket_decoded_tag) {
|
||||
if (mp.which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
const SubPacket &p = mp.decoded;
|
||||
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||
|
||||
@@ -539,7 +538,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
|
||||
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
|
||||
|
||||
switch (p.which_payload) {
|
||||
switch (p.which_payloadVariant) {
|
||||
case SubPacket_position_tag: {
|
||||
// handle a legacy position packet
|
||||
DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from);
|
||||
@@ -601,7 +600,7 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address)
|
||||
// Print error to screen and serial port
|
||||
String lcd = String("Critical error ") + code + "!\n";
|
||||
screen->print(lcd.c_str());
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=%x\n", code, address);
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
|
||||
|
||||
// Record error to DB
|
||||
myNodeInfo.error_code = code;
|
||||
|
||||
@@ -59,15 +59,15 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
// return (lastContactMsec != 0) &&
|
||||
|
||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
||||
switch (toRadioScratch.which_variant) {
|
||||
switch (toRadioScratch.which_payloadVariant) {
|
||||
case ToRadio_packet_tag: {
|
||||
MeshPacket &p = toRadioScratch.variant.packet;
|
||||
MeshPacket &p = toRadioScratch.packet;
|
||||
printPacket("PACKET FROM PHONE", &p);
|
||||
service.handleToRadio(p);
|
||||
break;
|
||||
}
|
||||
case ToRadio_want_config_id_tag:
|
||||
config_nonce = toRadioScratch.variant.want_config_id;
|
||||
config_nonce = toRadioScratch.want_config_id;
|
||||
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
|
||||
state = STATE_SEND_MY_INFO;
|
||||
|
||||
@@ -79,12 +79,12 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
|
||||
case ToRadio_set_owner_tag:
|
||||
DEBUG_MSG("Client is setting owner\n");
|
||||
handleSetOwner(toRadioScratch.variant.set_owner);
|
||||
handleSetOwner(toRadioScratch.set_owner);
|
||||
break;
|
||||
|
||||
case ToRadio_set_radio_tag:
|
||||
DEBUG_MSG("Client is setting radio\n");
|
||||
handleSetRadio(toRadioScratch.variant.set_radio);
|
||||
handleSetRadio(toRadioScratch.set_radio);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -131,22 +131,22 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled)
|
||||
? true
|
||||
: (gps && gps->isConnected()); // Update with latest GPS connect info
|
||||
fromRadioScratch.which_variant = FromRadio_my_info_tag;
|
||||
fromRadioScratch.variant.my_info = myNodeInfo;
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
|
||||
fromRadioScratch.my_info = myNodeInfo;
|
||||
state = STATE_SEND_RADIO;
|
||||
|
||||
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
|
||||
break;
|
||||
|
||||
case STATE_SEND_RADIO:
|
||||
fromRadioScratch.which_variant = FromRadio_radio_tag;
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_radio_tag;
|
||||
|
||||
fromRadioScratch.variant.radio = radioConfig;
|
||||
fromRadioScratch.radio = radioConfig;
|
||||
|
||||
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
|
||||
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
|
||||
// using to the app (so that even old phone apps work with new device loads).
|
||||
fromRadioScratch.variant.radio.preferences.ls_secs = getPref_ls_secs();
|
||||
fromRadioScratch.radio.preferences.ls_secs = getPref_ls_secs();
|
||||
|
||||
state = STATE_SEND_NODEINFO;
|
||||
break;
|
||||
@@ -158,8 +158,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
if (info) {
|
||||
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
|
||||
info->user.long_name);
|
||||
fromRadioScratch.which_variant = FromRadio_node_info_tag;
|
||||
fromRadioScratch.variant.node_info = *info;
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
|
||||
fromRadioScratch.node_info = *info;
|
||||
// Stay in current state until done sending nodeinfos
|
||||
} else {
|
||||
DEBUG_MSG("Done sending nodeinfos\n");
|
||||
@@ -171,8 +171,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
}
|
||||
|
||||
case STATE_SEND_COMPLETE_ID:
|
||||
fromRadioScratch.which_variant = FromRadio_config_complete_id_tag;
|
||||
fromRadioScratch.variant.config_complete_id = config_nonce;
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_config_complete_id_tag;
|
||||
fromRadioScratch.config_complete_id = config_nonce;
|
||||
config_nonce = 0;
|
||||
state = STATE_SEND_PACKETS;
|
||||
break;
|
||||
@@ -185,8 +185,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
printPacket("phone downloaded packet", packetForPhone);
|
||||
|
||||
// Encapsulate as a FromRadio packet
|
||||
fromRadioScratch.which_variant = FromRadio_packet_tag;
|
||||
fromRadioScratch.variant.packet = *packetForPhone;
|
||||
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;
|
||||
@@ -198,9 +198,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
}
|
||||
|
||||
// Do we have a message from the mesh?
|
||||
if (fromRadioScratch.which_variant != 0) {
|
||||
if (fromRadioScratch.which_payloadVariant != 0) {
|
||||
// Encapsulate as a FromRadio packet
|
||||
DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_variant);
|
||||
DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_payloadVariant);
|
||||
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
|
||||
DEBUG_MSG(", %d bytes\n", numbytes);
|
||||
return numbytes;
|
||||
|
||||
@@ -83,7 +83,7 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl)
|
||||
|
||||
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
|
||||
{
|
||||
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
||||
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
||||
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
|
||||
|
||||
return getPacketTime(pl);
|
||||
@@ -119,9 +119,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
{
|
||||
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);
|
||||
if (p->which_payload == MeshPacket_decoded_tag) {
|
||||
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
auto &s = p->decoded;
|
||||
switch (s.which_payload) {
|
||||
switch (s.which_payloadVariant) {
|
||||
case SubPacket_data_tag:
|
||||
DEBUG_MSG(" Portnum=%d", s.data.portnum);
|
||||
break;
|
||||
@@ -135,7 +135,7 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
DEBUG_MSG(" Payload:None");
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG(" Payload:%d", s.which_payload);
|
||||
DEBUG_MSG(" Payload:%d", s.which_payloadVariant);
|
||||
break;
|
||||
}
|
||||
if (s.want_response)
|
||||
@@ -147,10 +147,10 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
if (s.dest != 0)
|
||||
DEBUG_MSG(" dest=%08x", s.dest);
|
||||
|
||||
if (s.which_ack == SubPacket_success_id_tag)
|
||||
DEBUG_MSG(" successId=%08x", s.ack.success_id);
|
||||
else if (s.which_ack == SubPacket_fail_id_tag)
|
||||
DEBUG_MSG(" failId=%08x", s.ack.fail_id);
|
||||
if (s.which_ackVariant == SubPacket_success_id_tag)
|
||||
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
|
||||
else if (s.which_ackVariant == SubPacket_fail_id_tag)
|
||||
DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id);
|
||||
} else {
|
||||
DEBUG_MSG(" encrypted");
|
||||
}
|
||||
@@ -161,6 +161,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
if (p->rx_snr != 0.0) {
|
||||
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
|
||||
}
|
||||
if(p->priority != 0)
|
||||
DEBUG_MSG(" priority=%d", p->priority);
|
||||
|
||||
DEBUG_MSG(")\n");
|
||||
}
|
||||
|
||||
@@ -209,6 +212,38 @@ unsigned long hash(const char *str)
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save our frequency for later reuse.
|
||||
*/
|
||||
void RadioInterface::saveFreq(float freq)
|
||||
{
|
||||
savedFreq = freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save our channel for later reuse.
|
||||
*/
|
||||
void RadioInterface::saveChannelNum(uint32_t channel_num)
|
||||
{
|
||||
savedChannelNum = channel_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save our frequency for later reuse.
|
||||
*/
|
||||
float RadioInterface::getFreq()
|
||||
{
|
||||
return savedFreq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save our channel for later reuse.
|
||||
*/
|
||||
uint32_t RadioInterface::getChannelNum()
|
||||
{
|
||||
return savedChannelNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull our channel settings etc... from protobufs to the dumb interface settings
|
||||
*/
|
||||
@@ -261,18 +296,19 @@ void RadioInterface::applyModemConfig()
|
||||
assert(myRegion); // Should have been found in init
|
||||
|
||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||
int channel_num =
|
||||
(channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName)) % myRegion->numChannels;
|
||||
int channel_num = (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName)) % myRegion->numChannels;
|
||||
freq = myRegion->freq + 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("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
|
||||
DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
|
||||
DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
|
||||
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", freq);
|
||||
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
|
||||
|
||||
saveChannelNum(channel_num);
|
||||
saveFreq(freq);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,7 +351,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
|
||||
assert(!sendingPacket);
|
||||
|
||||
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
|
||||
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
||||
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
||||
|
||||
lastTxStart = millis();
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ class RadioInterface
|
||||
uint32_t shortPacketMsec;
|
||||
|
||||
protected:
|
||||
bool disabled = false;
|
||||
|
||||
float bw = 125;
|
||||
uint8_t sf = 9;
|
||||
uint8_t cr = 7;
|
||||
@@ -98,6 +100,9 @@ class RadioInterface
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep() { return true; }
|
||||
|
||||
/// Disable this interface (while disabled, no packets can be sent or received)
|
||||
void disable() { disabled = true; sleep(); }
|
||||
|
||||
/**
|
||||
* Send a packet (possibly by enquing in a private fifo). This routine will
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
@@ -105,6 +110,9 @@ class RadioInterface
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p) = 0;
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id) { return false; }
|
||||
|
||||
// methods from radiohead
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
@@ -133,9 +141,22 @@ class RadioInterface
|
||||
uint32_t getPacketTime(MeshPacket *p);
|
||||
uint32_t getPacketTime(uint32_t totalPacketLen);
|
||||
|
||||
/**
|
||||
* Get the channel we saved.
|
||||
*/
|
||||
uint32_t getChannelNum();
|
||||
|
||||
/**
|
||||
* Get the frequency we saved.
|
||||
*/
|
||||
float getFreq();
|
||||
|
||||
protected:
|
||||
int8_t power = 17; // Set by applyModemConfig()
|
||||
|
||||
float savedFreq;
|
||||
uint32_t savedChannelNum;
|
||||
|
||||
/***
|
||||
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the
|
||||
* PacketHeader & payload).
|
||||
@@ -157,6 +178,16 @@ class RadioInterface
|
||||
*/
|
||||
virtual void applyModemConfig();
|
||||
|
||||
/**
|
||||
* Save the frequency we selected for later reuse.
|
||||
*/
|
||||
virtual void saveFreq(float savedFreq);
|
||||
|
||||
/**
|
||||
* Save the chanel we selected for later reuse.
|
||||
*/
|
||||
virtual void saveChannelNum(uint32_t savedChannelNum);
|
||||
|
||||
private:
|
||||
/// Return 0 if sleep is okay
|
||||
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include "MeshTypes.h"
|
||||
#include "NodeDB.h"
|
||||
#include "SPILock.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "error.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <configuration.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
@@ -68,13 +68,12 @@ bool RadioLibInterface::canSendImmediately()
|
||||
bool busyTx = sendingPacket != NULL;
|
||||
bool busyRx = isReceiving && isActivelyReceiving();
|
||||
|
||||
|
||||
if (busyTx || busyRx) {
|
||||
if (busyTx)
|
||||
DEBUG_MSG("Can not send yet, busyTx\n");
|
||||
// If we've been trying to send the same packet more than one minute and we haven't gotten a
|
||||
// TX IRQ from the radio, the radio is probably broken.
|
||||
if (busyTx && (millis() - lastTxStart > 60000)){
|
||||
if (busyTx && (millis() - lastTxStart > 60000)) {
|
||||
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
|
||||
recordCriticalError(CriticalErrorCode_TransmitFailed);
|
||||
#ifndef NO_ESP32
|
||||
@@ -94,13 +93,18 @@ bool RadioLibInterface::canSendImmediately()
|
||||
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
||||
ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
{
|
||||
if (disabled) {
|
||||
packetPool.release(p);
|
||||
return ERRNO_DISABLED;
|
||||
}
|
||||
|
||||
// Sometimes when testing it is useful to be able to never turn on the xmitter
|
||||
#ifndef LORA_DISABLE_SENDING
|
||||
printPacket("enqueuing for send", p);
|
||||
uint32_t xmitMsec = getPacketTime(p);
|
||||
|
||||
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
|
||||
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
|
||||
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||
packetPool.release(p);
|
||||
@@ -110,7 +114,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
// Count the packet toward our TX airtime utilization.
|
||||
// We only count it if it can be added to the TX queue.
|
||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||
//airTime.logAirtime(TX_LOG, xmitMsec);
|
||||
// airTime.logAirtime(TX_LOG, xmitMsec);
|
||||
|
||||
// We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent
|
||||
// in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio
|
||||
@@ -119,19 +123,31 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
return res;
|
||||
#else
|
||||
packetPool.release(p);
|
||||
return ERRNO_UNKNOWN;
|
||||
return ERRNO_DISABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RadioLibInterface::canSleep()
|
||||
{
|
||||
bool res = txQueue.isEmpty();
|
||||
bool res = txQueue.empty();
|
||||
if (!res) // only print debug messages if we are vetoing sleep
|
||||
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
|
||||
{
|
||||
auto p = txQueue.remove(from, id);
|
||||
if (p)
|
||||
packetPool.release(p); // free the packet we just removed
|
||||
|
||||
bool result = (p != NULL);
|
||||
DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** radio helper thread callback.
|
||||
|
||||
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
|
||||
@@ -165,12 +181,12 @@ void RadioLibInterface::onNotify(uint32_t notification)
|
||||
|
||||
// If we are not currently in receive mode, then restart the timer and try again later (this can happen if the main thread
|
||||
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
|
||||
if (!txQueue.isEmpty()) {
|
||||
if (!txQueue.empty()) {
|
||||
if (!canSendImmediately()) {
|
||||
startTransmitTimer(); // try again in a little while
|
||||
} else {
|
||||
// Send any outgoing packets we have ready
|
||||
MeshPacket *txp = txQueue.dequeuePtr(0);
|
||||
MeshPacket *txp = txQueue.dequeue();
|
||||
assert(txp);
|
||||
startSend(txp);
|
||||
}
|
||||
@@ -186,7 +202,7 @@ void RadioLibInterface::onNotify(uint32_t notification)
|
||||
void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||
{
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.isEmpty()) {
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
||||
@@ -230,7 +246,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
|
||||
xmitMsec = getPacketTime(length);
|
||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
||||
//airTime.logAirtime(RX_ALL_LOG, xmitMsec);
|
||||
// airTime.logAirtime(RX_ALL_LOG, xmitMsec);
|
||||
|
||||
int state = iface->readData(radiobuf, length);
|
||||
if (state != ERR_NONE) {
|
||||
@@ -264,8 +280,8 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
|
||||
addReceiveMetadata(mp);
|
||||
|
||||
mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
|
||||
assert(((uint32_t) payloadLen) <= sizeof(mp->encrypted.bytes));
|
||||
mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
|
||||
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
|
||||
memcpy(mp->encrypted.bytes, payload, payloadLen);
|
||||
mp->encrypted.size = payloadLen;
|
||||
|
||||
@@ -273,7 +289,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
|
||||
xmitMsec = getPacketTime(mp);
|
||||
airTime->logAirtime(RX_LOG, xmitMsec);
|
||||
//airTime.logAirtime(RX_LOG, xmitMsec);
|
||||
// airTime.logAirtime(RX_LOG, xmitMsec);
|
||||
|
||||
deliverToReceiver(mp);
|
||||
}
|
||||
@@ -283,16 +299,21 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
/** start an immediate transmit */
|
||||
void RadioLibInterface::startSend(MeshPacket *txp)
|
||||
{
|
||||
printPacket("Starting low level send", txp);
|
||||
setStandby(); // Cancel any already in process receives
|
||||
printPacket("Starting low level send", txp);
|
||||
if (disabled) {
|
||||
DEBUG_MSG("startSend is dropping tx packet because we are disabled\n");
|
||||
packetPool.release(txp);
|
||||
} else {
|
||||
setStandby(); // Cancel any already in process receives
|
||||
|
||||
configHardwareForSend(); // must be after setStandby
|
||||
configHardwareForSend(); // must be after setStandby
|
||||
|
||||
size_t numbytes = beginSending(txp);
|
||||
size_t numbytes = beginSending(txp);
|
||||
|
||||
int res = iface->startTransmit(radiobuf, numbytes);
|
||||
assert(res == ERR_NONE);
|
||||
int res = iface->startTransmit(radiobuf, numbytes);
|
||||
assert(res == ERR_NONE);
|
||||
|
||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
|
||||
enableInterrupt(isrTxLevel0);
|
||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
|
||||
enableInterrupt(isrTxLevel0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "../concurrency/OSThread.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "MeshPacketQueue.h"
|
||||
|
||||
#ifdef CubeCell_BoardPlus
|
||||
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
|
||||
@@ -74,7 +75,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
*/
|
||||
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
|
||||
|
||||
PointerQueue<MeshPacket> txQueue = PointerQueue<MeshPacket>(MAX_TX_QUEUE);
|
||||
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -136,6 +137,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
*/
|
||||
virtual bool isActivelyReceiving() = 0;
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id);
|
||||
|
||||
private:
|
||||
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
|
||||
* the transmit
|
||||
|
||||
@@ -65,8 +65,8 @@ void ReliableRouter::sniffReceived(const MeshPacket *p)
|
||||
|
||||
// If the payload is valid, look for ack/nak
|
||||
|
||||
PacketId ackId = p->decoded.which_ack == SubPacket_success_id_tag ? p->decoded.ack.success_id : 0;
|
||||
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
|
||||
PacketId ackId = p->decoded.which_ackVariant == SubPacket_success_id_tag ? p->decoded.ackVariant.success_id : 0;
|
||||
PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
|
||||
|
||||
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
||||
if (ackId || nakId) {
|
||||
|
||||
@@ -88,7 +88,7 @@ MeshPacket *Router::allocForSending()
|
||||
{
|
||||
MeshPacket *p = packetPool.allocZeroed();
|
||||
|
||||
p->which_payload = MeshPacket_decoded_tag; // Assume payload is decoded at start.
|
||||
p->which_payloadVariant = MeshPacket_decoded_tag; // Assume payload is decoded at start.
|
||||
p->from = nodeDB.getNodeNum();
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->hop_limit = HOP_RELIABLE;
|
||||
@@ -110,20 +110,23 @@ void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom)
|
||||
DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
|
||||
if (!err) {
|
||||
p->decoded.ack.success_id = idFrom;
|
||||
p->decoded.which_ack = SubPacket_success_id_tag;
|
||||
p->decoded.ackVariant.success_id = idFrom;
|
||||
p->decoded.which_ackVariant = SubPacket_success_id_tag;
|
||||
} else {
|
||||
p->decoded.ack.fail_id = idFrom;
|
||||
p->decoded.which_ack = SubPacket_fail_id_tag;
|
||||
p->decoded.ackVariant.fail_id = idFrom;
|
||||
p->decoded.which_ackVariant = SubPacket_fail_id_tag;
|
||||
|
||||
// Also send back the error reason
|
||||
p->decoded.which_payload = SubPacket_error_reason_tag;
|
||||
p->decoded.which_payloadVariant = SubPacket_error_reason_tag;
|
||||
p->decoded.error_reason = err;
|
||||
}
|
||||
p->priority = MeshPacket_Priority_ACK;
|
||||
|
||||
sendLocal(p); // we sometimes send directly to the local node
|
||||
}
|
||||
|
||||
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
{
|
||||
// No need to deliver externally if the destination is the local node
|
||||
@@ -160,7 +163,7 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
{
|
||||
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
|
||||
|
||||
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
|
||||
PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
|
||||
assert(
|
||||
!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert
|
||||
|
||||
@@ -170,11 +173,11 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
|
||||
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
|
||||
|
||||
assert(p->which_payload == MeshPacket_encrypted_tag ||
|
||||
p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
|
||||
assert(p->which_payloadVariant == MeshPacket_encrypted_tag ||
|
||||
p->which_payloadVariant == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
|
||||
|
||||
// First convert from protobufs to raw bytes
|
||||
if (p->which_payload == MeshPacket_decoded_tag) {
|
||||
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
|
||||
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
|
||||
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded);
|
||||
@@ -185,7 +188,7 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
// Copy back into the packet and set the variant type
|
||||
memcpy(p->encrypted.bytes, bytes, numbytes);
|
||||
p->encrypted.size = numbytes;
|
||||
p->which_payload = MeshPacket_encrypted_tag;
|
||||
p->which_payloadVariant = MeshPacket_encrypted_tag;
|
||||
}
|
||||
|
||||
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)
|
||||
@@ -199,6 +202,13 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
} */
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
bool Router::cancelSending(NodeNum from, PacketId id) {
|
||||
return iface ? iface->cancelSending(from, id) : false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
|
||||
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
|
||||
@@ -211,10 +221,10 @@ void Router::sniffReceived(const MeshPacket *p)
|
||||
|
||||
bool Router::perhapsDecode(MeshPacket *p)
|
||||
{
|
||||
if (p->which_payload == MeshPacket_decoded_tag)
|
||||
if (p->which_payloadVariant == MeshPacket_decoded_tag)
|
||||
return true; // If packet was already decoded just return
|
||||
|
||||
assert(p->which_payload == MeshPacket_encrypted_tag);
|
||||
assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
|
||||
|
||||
// FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without
|
||||
// being able to decrypt their data.
|
||||
@@ -230,7 +240,7 @@ bool Router::perhapsDecode(MeshPacket *p)
|
||||
return false;
|
||||
} else {
|
||||
// parsing was successful
|
||||
p->which_payload = MeshPacket_decoded_tag;
|
||||
p->which_payloadVariant = MeshPacket_decoded_tag;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,12 @@ class Router : protected concurrency::OSThread
|
||||
*/
|
||||
ErrorCode sendLocal(MeshPacket *p);
|
||||
|
||||
/// Allocate and return a meshpacket which defaults as send to broadcast from the current node.
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
bool cancelSending(NodeNum from, PacketId id);
|
||||
|
||||
/** Allocate and return a meshpacket which defaults as send to broadcast from the current node.
|
||||
* The returned packet is guaranteed to have a unique packet ID already assigned
|
||||
*/
|
||||
MeshPacket *allocForSending();
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@ class SinglePortPlugin : public MeshPlugin
|
||||
{
|
||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||
MeshPacket *p = router->allocForSending();
|
||||
p->decoded.which_payload = SubPacket_data_tag;
|
||||
p->decoded.which_payloadVariant = SubPacket_data_tag;
|
||||
p->decoded.data.portnum = ourPortNum;
|
||||
|
||||
return p;
|
||||
|
||||
@@ -84,8 +84,8 @@ void StreamAPI::emitRebooted()
|
||||
{
|
||||
// In case we send a FromRadio packet
|
||||
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
|
||||
fromRadioScratch.which_variant = FromRadio_rebooted_tag;
|
||||
fromRadioScratch.variant.rebooted = true;
|
||||
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
|
||||
fromRadioScratch.rebooted = true;
|
||||
|
||||
DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
||||
|
||||
@@ -80,10 +80,10 @@ extern const pb_msgdesc_t DeviceState_msg;
|
||||
#define DeviceState_fields &DeviceState_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define DeviceState_size 6239
|
||||
#define DeviceState_size 6266
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -58,3 +58,4 @@ PB_BIND(ToRadio, ToRadio, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -83,6 +83,16 @@ typedef enum _CriticalErrorCode {
|
||||
CriticalErrorCode_TransmitFailed = 8
|
||||
} CriticalErrorCode;
|
||||
|
||||
typedef enum _MeshPacket_Priority {
|
||||
MeshPacket_Priority_UNSET = 0,
|
||||
MeshPacket_Priority_MIN = 1,
|
||||
MeshPacket_Priority_BACKGROUND = 10,
|
||||
MeshPacket_Priority_DEFAULT = 64,
|
||||
MeshPacket_Priority_RELIABLE = 70,
|
||||
MeshPacket_Priority_ACK = 120,
|
||||
MeshPacket_Priority_MAX = 127
|
||||
} MeshPacket_Priority;
|
||||
|
||||
typedef enum _ChannelSettings_ModemConfig {
|
||||
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
|
||||
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
|
||||
@@ -193,6 +203,11 @@ typedef struct _RadioConfig_UserPreferences {
|
||||
bool ext_notification_plugin_active;
|
||||
bool ext_notification_plugin_alert_message;
|
||||
bool ext_notification_plugin_alert_bell;
|
||||
bool range_test_plugin_enabled;
|
||||
uint32_t range_test_plugin_sender;
|
||||
bool range_test_plugin_save;
|
||||
bool store_forward_plugin_enabled;
|
||||
uint32_t store_forward_plugin_records;
|
||||
} RadioConfig_UserPreferences;
|
||||
|
||||
typedef struct _RouteDiscovery {
|
||||
@@ -225,7 +240,7 @@ typedef struct _RadioConfig {
|
||||
} RadioConfig;
|
||||
|
||||
typedef struct _SubPacket {
|
||||
pb_size_t which_payload;
|
||||
pb_size_t which_payloadVariant;
|
||||
union {
|
||||
Position position;
|
||||
Data data;
|
||||
@@ -237,11 +252,11 @@ typedef struct _SubPacket {
|
||||
uint32_t original_id;
|
||||
bool want_response;
|
||||
uint32_t dest;
|
||||
pb_size_t which_ack;
|
||||
pb_size_t which_ackVariant;
|
||||
union {
|
||||
uint32_t success_id;
|
||||
uint32_t fail_id;
|
||||
} ack;
|
||||
} ackVariant;
|
||||
uint32_t source;
|
||||
} SubPacket;
|
||||
|
||||
@@ -249,7 +264,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
|
||||
typedef struct _MeshPacket {
|
||||
uint32_t from;
|
||||
uint32_t to;
|
||||
pb_size_t which_payload;
|
||||
pb_size_t which_payloadVariant;
|
||||
union {
|
||||
SubPacket decoded;
|
||||
MeshPacket_encrypted_t encrypted;
|
||||
@@ -260,11 +275,12 @@ typedef struct _MeshPacket {
|
||||
uint32_t rx_time;
|
||||
uint32_t hop_limit;
|
||||
bool want_ack;
|
||||
MeshPacket_Priority priority;
|
||||
} MeshPacket;
|
||||
|
||||
typedef struct _FromRadio {
|
||||
uint32_t num;
|
||||
pb_size_t which_variant;
|
||||
pb_size_t which_payloadVariant;
|
||||
union {
|
||||
MeshPacket packet;
|
||||
MyNodeInfo my_info;
|
||||
@@ -274,18 +290,18 @@ typedef struct _FromRadio {
|
||||
uint32_t config_complete_id;
|
||||
bool rebooted;
|
||||
ChannelSettings channel;
|
||||
} variant;
|
||||
};
|
||||
} FromRadio;
|
||||
|
||||
typedef struct _ToRadio {
|
||||
pb_size_t which_variant;
|
||||
pb_size_t which_payloadVariant;
|
||||
union {
|
||||
MeshPacket packet;
|
||||
uint32_t want_config_id;
|
||||
RadioConfig set_radio;
|
||||
User set_owner;
|
||||
ChannelSettings set_channel;
|
||||
} variant;
|
||||
};
|
||||
} ToRadio;
|
||||
|
||||
|
||||
@@ -318,6 +334,10 @@ typedef struct _ToRadio {
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1))
|
||||
|
||||
#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET
|
||||
#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX
|
||||
#define _MeshPacket_Priority_ARRAYSIZE ((MeshPacket_Priority)(MeshPacket_Priority_MAX+1))
|
||||
|
||||
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
|
||||
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
|
||||
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
|
||||
@@ -337,10 +357,10 @@ extern "C" {
|
||||
#define User_init_default {"", "", "", {0}}
|
||||
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0}
|
||||
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0}
|
||||
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
||||
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
||||
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
||||
#define RadioConfig_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}
|
||||
#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}
|
||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
||||
@@ -351,10 +371,10 @@ extern "C" {
|
||||
#define User_init_zero {"", "", "", {0}}
|
||||
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0}
|
||||
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0}
|
||||
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
||||
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
||||
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
||||
#define RadioConfig_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}
|
||||
#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}
|
||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||
@@ -435,6 +455,11 @@ extern "C" {
|
||||
#define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129
|
||||
#define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130
|
||||
#define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131
|
||||
#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132
|
||||
#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133
|
||||
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136
|
||||
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
|
||||
#define RouteDiscovery_route_tag 2
|
||||
#define User_id_tag 1
|
||||
#define User_long_name_tag 2
|
||||
@@ -469,6 +494,7 @@ extern "C" {
|
||||
#define MeshPacket_rx_time_tag 9
|
||||
#define MeshPacket_hop_limit_tag 10
|
||||
#define MeshPacket_want_ack_tag 11
|
||||
#define MeshPacket_priority_tag 12
|
||||
#define FromRadio_num_tag 1
|
||||
#define FromRadio_packet_tag 2
|
||||
#define FromRadio_my_info_tag 3
|
||||
@@ -514,40 +540,41 @@ X(a, STATIC, REPEATED, INT32, route, 2)
|
||||
#define RouteDiscovery_DEFAULT NULL
|
||||
|
||||
#define SubPacket_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,position,position), 1) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,data,data), 3) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,user,user), 4) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,route_request,route_request), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,route_reply,route_reply), 7) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,error_reason,error_reason), 13) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,position), 1) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,data,data), 3) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,user,user), 4) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_request,route_request), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_reply,route_reply), 7) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payloadVariant,error_reason,error_reason), 13) \
|
||||
X(a, STATIC, SINGULAR, UINT32, original_id, 2) \
|
||||
X(a, STATIC, SINGULAR, BOOL, want_response, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, dest, 9) \
|
||||
X(a, STATIC, ONEOF, UINT32, (ack,success_id,ack.success_id), 10) \
|
||||
X(a, STATIC, ONEOF, UINT32, (ack,fail_id,ack.fail_id), 11) \
|
||||
X(a, STATIC, ONEOF, UINT32, (ackVariant,success_id,ackVariant.success_id), 10) \
|
||||
X(a, STATIC, ONEOF, UINT32, (ackVariant,fail_id,ackVariant.fail_id), 11) \
|
||||
X(a, STATIC, SINGULAR, UINT32, source, 12)
|
||||
#define SubPacket_CALLBACK NULL
|
||||
#define SubPacket_DEFAULT NULL
|
||||
#define SubPacket_payload_position_MSGTYPE Position
|
||||
#define SubPacket_payload_data_MSGTYPE Data
|
||||
#define SubPacket_payload_user_MSGTYPE User
|
||||
#define SubPacket_payload_route_request_MSGTYPE RouteDiscovery
|
||||
#define SubPacket_payload_route_reply_MSGTYPE RouteDiscovery
|
||||
#define SubPacket_payloadVariant_position_MSGTYPE Position
|
||||
#define SubPacket_payloadVariant_data_MSGTYPE Data
|
||||
#define SubPacket_payloadVariant_user_MSGTYPE User
|
||||
#define SubPacket_payloadVariant_route_request_MSGTYPE RouteDiscovery
|
||||
#define SubPacket_payloadVariant_route_reply_MSGTYPE RouteDiscovery
|
||||
|
||||
#define MeshPacket_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, from, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, to, 2) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,decoded,decoded), 3) \
|
||||
X(a, STATIC, ONEOF, BYTES, (payload,encrypted,encrypted), 8) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 3) \
|
||||
X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, id, 6) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, rx_time, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, want_ack, 11)
|
||||
X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \
|
||||
X(a, STATIC, SINGULAR, UENUM, priority, 12)
|
||||
#define MeshPacket_CALLBACK NULL
|
||||
#define MeshPacket_DEFAULT NULL
|
||||
#define MeshPacket_payload_decoded_MSGTYPE SubPacket
|
||||
#define MeshPacket_payloadVariant_decoded_MSGTYPE SubPacket
|
||||
|
||||
#define ChannelSettings_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \
|
||||
@@ -609,7 +636,12 @@ X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \
|
||||
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \
|
||||
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \
|
||||
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131)
|
||||
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \
|
||||
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \
|
||||
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
|
||||
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
|
||||
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \
|
||||
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137)
|
||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||
#define RadioConfig_UserPreferences_DEFAULT NULL
|
||||
|
||||
@@ -652,35 +684,35 @@ X(a, STATIC, SINGULAR, UENUM, level, 4)
|
||||
|
||||
#define FromRadio_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, num, 1) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 2) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,my_info,variant.my_info), 3) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,node_info,variant.node_info), 4) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,radio,variant.radio), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,log_record,variant.log_record), 7) \
|
||||
X(a, STATIC, ONEOF, UINT32, (variant,config_complete_id,variant.config_complete_id), 8) \
|
||||
X(a, STATIC, ONEOF, BOOL, (variant,rebooted,variant.rebooted), 9) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,channel,variant.channel), 10)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,radio,radio), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,channel), 10)
|
||||
#define FromRadio_CALLBACK NULL
|
||||
#define FromRadio_DEFAULT NULL
|
||||
#define FromRadio_variant_packet_MSGTYPE MeshPacket
|
||||
#define FromRadio_variant_my_info_MSGTYPE MyNodeInfo
|
||||
#define FromRadio_variant_node_info_MSGTYPE NodeInfo
|
||||
#define FromRadio_variant_radio_MSGTYPE RadioConfig
|
||||
#define FromRadio_variant_log_record_MSGTYPE LogRecord
|
||||
#define FromRadio_variant_channel_MSGTYPE ChannelSettings
|
||||
#define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket
|
||||
#define FromRadio_payloadVariant_my_info_MSGTYPE MyNodeInfo
|
||||
#define FromRadio_payloadVariant_node_info_MSGTYPE NodeInfo
|
||||
#define FromRadio_payloadVariant_radio_MSGTYPE RadioConfig
|
||||
#define FromRadio_payloadVariant_log_record_MSGTYPE LogRecord
|
||||
#define FromRadio_payloadVariant_channel_MSGTYPE ChannelSettings
|
||||
|
||||
#define ToRadio_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 1) \
|
||||
X(a, STATIC, ONEOF, UINT32, (variant,want_config_id,variant.want_config_id), 100) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,variant.set_radio), 101) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,variant.set_channel), 103)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 1) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,set_radio), 101) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,set_owner), 102) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,set_channel), 103)
|
||||
#define ToRadio_CALLBACK NULL
|
||||
#define ToRadio_DEFAULT NULL
|
||||
#define ToRadio_variant_packet_MSGTYPE MeshPacket
|
||||
#define ToRadio_variant_set_radio_MSGTYPE RadioConfig
|
||||
#define ToRadio_variant_set_owner_MSGTYPE User
|
||||
#define ToRadio_variant_set_channel_MSGTYPE ChannelSettings
|
||||
#define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket
|
||||
#define ToRadio_payloadVariant_set_radio_MSGTYPE RadioConfig
|
||||
#define ToRadio_payloadVariant_set_owner_MSGTYPE User
|
||||
#define ToRadio_payloadVariant_set_channel_MSGTYPE ChannelSettings
|
||||
|
||||
extern const pb_msgdesc_t Position_msg;
|
||||
extern const pb_msgdesc_t Data_msg;
|
||||
@@ -719,15 +751,15 @@ extern const pb_msgdesc_t ToRadio_msg;
|
||||
#define User_size 72
|
||||
#define RouteDiscovery_size 88
|
||||
#define SubPacket_size 275
|
||||
#define MeshPacket_size 320
|
||||
#define MeshPacket_size 322
|
||||
#define ChannelSettings_size 95
|
||||
#define RadioConfig_size 382
|
||||
#define RadioConfig_UserPreferences_size 282
|
||||
#define RadioConfig_size 405
|
||||
#define RadioConfig_UserPreferences_size 305
|
||||
#define NodeInfo_size 132
|
||||
#define MyNodeInfo_size 106
|
||||
#define LogRecord_size 81
|
||||
#define FromRadio_size 391
|
||||
#define ToRadio_size 386
|
||||
#define FromRadio_size 414
|
||||
#define ToRadio_size 409
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -20,6 +20,7 @@ typedef enum _PortNum {
|
||||
PortNum_IP_TUNNEL_APP = 33,
|
||||
PortNum_SERIAL_APP = 64,
|
||||
PortNum_STORE_FORWARD_APP = 65,
|
||||
PortNum_RANGE_TEST_APP = 66,
|
||||
PortNum_PRIVATE_APP = 256,
|
||||
PortNum_ATAK_FORWARDER = 257
|
||||
} PortNum;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <HTTPMultipartBodyParser.hpp>
|
||||
#include <HTTPURLEncodedBodyParser.hpp>
|
||||
#include <SPIFFS.h>
|
||||
#include "RadioLibInterface.h"
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
@@ -928,10 +929,17 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
res->printf("\"has_battery\": %s,\n", BoolToString(powerStatus->getHasBattery()));
|
||||
res->printf("\"has_usb\": %s,\n", BoolToString(powerStatus->getHasUSB()));
|
||||
res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging()));
|
||||
res->println("},");
|
||||
|
||||
res->println("\"radio\": {");
|
||||
res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq());
|
||||
res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum());
|
||||
res->println("}");
|
||||
|
||||
res->println("},");
|
||||
|
||||
|
||||
|
||||
res->println("\"status\": \"ok\"");
|
||||
res->println("}");
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/*
|
||||
|
||||
Documentation:
|
||||
https://github.com/mc-hamster/Meshtastic-device/blob/master/docs/software/plugins/ExternalNotificationPlugin.md
|
||||
https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/plugins/ExternalNotificationPlugin.md
|
||||
|
||||
This plugin supports:
|
||||
https://github.com/meshtastic/Meshtastic-device/issues/654
|
||||
|
||||
@@ -28,9 +28,15 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p)
|
||||
|
||||
void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
// cancel any not yet sent (now stale) position packets
|
||||
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
||||
service.cancelSending(prevPacketId);
|
||||
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
p->priority = MeshPacket_Priority_BACKGROUND;
|
||||
prevPacketId = p->id;
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
@@ -42,3 +48,26 @@ MeshPacket *NodeInfoPlugin::allocReply()
|
||||
DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
|
||||
return allocDataProtobuf(u);
|
||||
}
|
||||
|
||||
NodeInfoPlugin::NodeInfoPlugin()
|
||||
: ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoPlugin")
|
||||
{
|
||||
setIntervalFromNow(30 *
|
||||
1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
|
||||
}
|
||||
|
||||
int32_t NodeInfoPlugin::runOnce()
|
||||
{
|
||||
static uint32_t currentGeneration;
|
||||
|
||||
// If we changed channels, ask everyone else for their latest info
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
|
||||
assert(nodeInfoPlugin);
|
||||
nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
|
||||
|
||||
return getPref_position_broadcast_secs() * 1000;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,18 @@
|
||||
/**
|
||||
* NodeInfo plugin for sending/receiving NodeInfos into the mesh
|
||||
*/
|
||||
class NodeInfoPlugin : public ProtobufPlugin<User>
|
||||
class NodeInfoPlugin : public ProtobufPlugin<User>, private concurrency::OSThread
|
||||
{
|
||||
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
|
||||
PacketId prevPacketId = 0;
|
||||
|
||||
uint32_t currentGeneration = 0;
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
NodeInfoPlugin() : ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields) {}
|
||||
|
||||
NodeInfoPlugin();
|
||||
|
||||
/**
|
||||
* Send our NodeInfo into the mesh
|
||||
*/
|
||||
@@ -27,6 +31,9 @@ class NodeInfoPlugin : public ProtobufPlugin<User>
|
||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||
virtual MeshPacket *allocReply();
|
||||
|
||||
/** Does our periodic broadcast */
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
extern NodeInfoPlugin *nodeInfoPlugin;
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "plugins/ExternalNotificationPlugin.h"
|
||||
#include "plugins/NodeInfoPlugin.h"
|
||||
#include "plugins/PositionPlugin.h"
|
||||
#include "plugins/RangeTestPlugin.h"
|
||||
#include "plugins/RemoteHardwarePlugin.h"
|
||||
#include "plugins/ReplyPlugin.h"
|
||||
#include "plugins/SerialPlugin.h"
|
||||
#include "plugins/StoreForwardPlugin.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
|
||||
/**
|
||||
@@ -24,7 +26,12 @@ void setupPlugins()
|
||||
#ifndef NO_ESP32
|
||||
// Only run on an esp32 based device.
|
||||
|
||||
new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org
|
||||
new ExternalNotificationPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org
|
||||
/*
|
||||
Maintained by MC Hamster (Jm Casler) jm@casler.org
|
||||
*/
|
||||
new SerialPlugin();
|
||||
new ExternalNotificationPlugin();
|
||||
//storeForwardPlugin = new StoreForwardPlugin();
|
||||
rangeTestPlugin = new RangeTestPlugin();
|
||||
#endif
|
||||
}
|
||||
@@ -7,6 +7,14 @@
|
||||
|
||||
PositionPlugin *positionPlugin;
|
||||
|
||||
PositionPlugin::PositionPlugin()
|
||||
: ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin")
|
||||
{
|
||||
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 &p)
|
||||
{
|
||||
// FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us
|
||||
@@ -31,16 +39,51 @@ MeshPacket *PositionPlugin::allocReply()
|
||||
{
|
||||
NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position
|
||||
assert(node->has_position);
|
||||
|
||||
return allocDataProtobuf(node->position);
|
||||
|
||||
Position p = node->position;
|
||||
|
||||
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
|
||||
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
|
||||
// devices can get time.
|
||||
if (getRTCQuality() < RTCQualityGPS) {
|
||||
DEBUG_MSG("Stripping time %u from position send\n", p.time);
|
||||
p.time = 0;
|
||||
} else
|
||||
DEBUG_MSG("Providing time to mesh %u\n", p.time);
|
||||
|
||||
return allocDataProtobuf(p);
|
||||
}
|
||||
|
||||
void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
// cancel any not yet sent (now stale) position packets
|
||||
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
||||
service.cancelSending(prevPacketId);
|
||||
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
p->priority = MeshPacket_Priority_BACKGROUND;
|
||||
prevPacketId = p->id;
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
int32_t PositionPlugin::runOnce()
|
||||
{
|
||||
|
||||
// We limit our GPS broadcasts to a max rate
|
||||
uint32_t now = millis();
|
||||
if (lastGpsSend == 0 || now - lastGpsSend >= getPref_position_broadcast_secs() * 1000) {
|
||||
lastGpsSend = now;
|
||||
|
||||
// If we changed channels, ask everyone else for their latest info
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
}
|
||||
|
||||
return 5000; // to save power only wake for our callback occasionally
|
||||
}
|
||||
@@ -1,17 +1,27 @@
|
||||
#pragma once
|
||||
#include "ProtobufPlugin.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
/**
|
||||
* Position plugin for sending/receiving positions into the mesh
|
||||
*/
|
||||
class PositionPlugin : public ProtobufPlugin<Position>
|
||||
class PositionPlugin : public ProtobufPlugin<Position>, private concurrency::OSThread
|
||||
{
|
||||
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
|
||||
PacketId prevPacketId = 0;
|
||||
|
||||
/// We limit our GPS broadcasts to a max rate
|
||||
uint32_t lastGpsSend = 0;
|
||||
|
||||
/// We force a rebroadcast if the radio settings change
|
||||
uint32_t currentGeneration = 0;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
PositionPlugin() : ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields) {}
|
||||
|
||||
PositionPlugin();
|
||||
|
||||
/**
|
||||
* Send our position into the mesh
|
||||
*/
|
||||
@@ -28,6 +38,9 @@ class PositionPlugin : public ProtobufPlugin<Position>
|
||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||
virtual MeshPacket *allocReply();
|
||||
|
||||
/** Does our periodic broadcast */
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
extern PositionPlugin *positionPlugin;
|
||||
173
src/plugins/RangeTestPlugin.cpp
Normal file
173
src/plugins/RangeTestPlugin.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "RangeTestPlugin.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
As a sender, I can send packets every n-seonds. These packets include an incramented PacketID.
|
||||
|
||||
As a receiver, I can receive packets from multiple senders. These packets can be saved to the spiffs.
|
||||
|
||||
*/
|
||||
|
||||
RangeTestPlugin *rangeTestPlugin;
|
||||
RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
|
||||
RangeTestPlugin::RangeTestPlugin() : concurrency::OSThread("RangeTestPlugin") {}
|
||||
|
||||
uint16_t packetSequence = 0;
|
||||
|
||||
// char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
|
||||
int32_t RangeTestPlugin::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// radioConfig.preferences.range_test_plugin_enabled = 1;
|
||||
// radioConfig.preferences.range_test_plugin_sender = 0;
|
||||
// radioConfig.preferences.fixed_position = 1;
|
||||
|
||||
uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
// Interface with the serial peripheral from in here.
|
||||
|
||||
rangeTestPluginRadio = new RangeTestPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Sender\n");
|
||||
return (senderHeartbeat);
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Receiver\n");
|
||||
return (500);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
// If sender
|
||||
DEBUG_MSG("Range Test Plugin - Sending heartbeat every %d ms\n", (senderHeartbeat));
|
||||
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("pref.fixed_position() %d\n", radioConfig.preferences.fixed_position);
|
||||
|
||||
rangeTestPluginRadio->sendPayload();
|
||||
return ((senderHeartbeat));
|
||||
} else {
|
||||
// Otherwise, we're a receiver.
|
||||
|
||||
return (500);
|
||||
}
|
||||
// TBD
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin - Disabled\n");
|
||||
}
|
||||
|
||||
return (INT32_MAX);
|
||||
#endif
|
||||
}
|
||||
|
||||
MeshPacket *RangeTestPluginRadio::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = true;
|
||||
|
||||
packetSequence++;
|
||||
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "seq %d", packetSequence);
|
||||
|
||||
p->decoded.data.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.data.payload.bytes, heartbeatString, p->decoded.data.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
|
||||
auto &p = mp.decoded.data;
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
if (mp.from != nodeDB.getNodeNum()) {
|
||||
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
// Serial2.printf("%s", p.payload.bytes);
|
||||
/*
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
NodeInfo *n = nodeDB.getNode(mp.from);
|
||||
|
||||
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
||||
DEBUG_MSG("p.payload.size %d\n", p.payload.size);
|
||||
DEBUG_MSG("---- Received Packet:\n");
|
||||
DEBUG_MSG("mp.from %d\n", mp.from);
|
||||
DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr);
|
||||
DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit);
|
||||
DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i);
|
||||
DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i);
|
||||
DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n");
|
||||
DEBUG_MSG("n->user.long_name %s\n", n->user.long_name);
|
||||
DEBUG_MSG("n->user.short_name %s\n", n->user.short_name);
|
||||
DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr);
|
||||
DEBUG_MSG("n->has_position %d\n", n->has_position);
|
||||
DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i);
|
||||
DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i);
|
||||
DEBUG_MSG("n->position.battery_level %d\n", n->position.battery_level);
|
||||
DEBUG_MSG("---- Current device location information:\n");
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
49
src/plugins/RangeTestPlugin.h
Normal file
49
src/plugins/RangeTestPlugin.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "SinglePortPlugin.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
class RangeTestPlugin : private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
public:
|
||||
RangeTestPlugin();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
extern RangeTestPlugin *rangeTestPlugin;
|
||||
|
||||
/*
|
||||
* Radio interface for RangeTestPlugin
|
||||
*
|
||||
*/
|
||||
class RangeTestPluginRadio : public SinglePortPlugin
|
||||
{
|
||||
uint32_t lastRxID;
|
||||
|
||||
public:
|
||||
|
||||
RangeTestPluginRadio() : SinglePortPlugin("RangeTestPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
protected:
|
||||
virtual MeshPacket *allocReply();
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
156
src/plugins/StoreForwardPlugin.cpp
Normal file
156
src/plugins/StoreForwardPlugin.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "StoreForwardPlugin.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define STORE_RECORDS 5000
|
||||
#define BYTES_PER_RECORDS 512
|
||||
|
||||
struct sfRecord
|
||||
{
|
||||
uint8_t bytes[BYTES_PER_RECORDS];
|
||||
uint32_t timestamp; // Time the packet was received
|
||||
};
|
||||
|
||||
struct sfRecord records[STORE_RECORDS];
|
||||
|
||||
#define STOREFORWARDPLUGIN_ENABLED 0
|
||||
|
||||
StoreForwardPlugin *storeForwardPlugin;
|
||||
StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
|
||||
StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("SerialPlugin") {}
|
||||
|
||||
// char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
|
||||
int32_t StoreForwardPlugin::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
//radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
//radioConfig.preferences.store_forward_plugin_records = 80;
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
// Interface with the serial peripheral from in here.
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin\n");
|
||||
|
||||
// Router
|
||||
if (radioConfig.preferences.is_router) {
|
||||
if (ESP.getPsramSize()) {
|
||||
if (ESP.getFreePsram() <= 1024 * 1024) {
|
||||
// Do the startup here
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device doesn't have PSRAM.\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
// Non-Router
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
storeForwardPluginRadio = new StoreForwardPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
} else {
|
||||
// TBD
|
||||
}
|
||||
|
||||
return (10);
|
||||
} else {
|
||||
DEBUG_MSG("Store & Forward Plugin - Disabled\n");
|
||||
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
MeshPacket *StoreForwardPluginRadio::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
//p->want_ack = SERIALPLUGIN_ACK;
|
||||
|
||||
// p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
|
||||
// memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
if (STOREFORWARDPLUGIN_ENABLED) {
|
||||
|
||||
auto &p = mp.decoded.data;
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
if (mp.from == nodeDB.getNodeNum()) {
|
||||
|
||||
/*
|
||||
* If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX
|
||||
* of the serial interface.
|
||||
*/
|
||||
if (radioConfig.preferences.serialplugin_echo) {
|
||||
|
||||
// For some reason, we get the packet back twice when we send out of the radio.
|
||||
// TODO: need to find out why.
|
||||
if (lastRxID != mp.id) {
|
||||
lastRxID = mp.id;
|
||||
// DEBUG_MSG("* * Message came this device\n");
|
||||
// Serial2.println("* * Message came this device");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Serial Plugin Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
54
src/plugins/StoreForwardPlugin.h
Normal file
54
src/plugins/StoreForwardPlugin.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "SinglePortPlugin.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
class StoreForwardPlugin : private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
public:
|
||||
StoreForwardPlugin();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
|
||||
extern StoreForwardPlugin *storeForwardPlugin;
|
||||
|
||||
/*
|
||||
* Radio interface for SerialPlugin
|
||||
*
|
||||
*/
|
||||
class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
{
|
||||
uint32_t lastRxID;
|
||||
|
||||
public:
|
||||
/*
|
||||
TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here
|
||||
from the main code.
|
||||
*/
|
||||
|
||||
// SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
StoreForwardPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {}
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
protected:
|
||||
virtual MeshPacket *allocReply();
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 1
|
||||
minor = 1
|
||||
build = 42
|
||||
build = 47
|
||||
|
||||
Reference in New Issue
Block a user