Compare commits

..

46 Commits

Author SHA1 Message Date
Kevin Hester
c0fbfccf43 Merge pull request #689 from geeksville/dev
Dev
2021-02-14 13:48:39 +08:00
Kevin Hester
51ccc3aa9e 1.1.47 2021-02-14 12:28:27 +08:00
Kevin Hester
e35f137986 clean up nodeinfo broadcasts and move into plugin 2021-02-14 12:27:10 +08:00
Kevin Hester
71c35304d6 delay position plugin start until 60 secs after first boot 2021-02-14 12:26:51 +08:00
Kevin Hester
c1733a4ac6 Merge remote-tracking branch 'root/master' into dev 2021-02-14 12:07:11 +08:00
Kevin Hester
66a7e8eab9 oops - we were never sending 'fixed' gps positions to other nodes 2021-02-14 12:02:24 +08:00
Kevin Hester
a872231f8a clean up position broadcasts, send them even if we don't have gps lock 2021-02-14 11:57:48 +08:00
Kevin Hester
52ec4d511c oops - we weren't properly stripping timestamps from new style positions 2021-02-14 11:37:32 +08:00
Jm Casler
aa7fb86798 Merge pull request #687 from sachaw/master
Fix report formatting
2021-02-13 14:02:12 -08:00
Sacha Weatherstone
875eeb699c Fix report formatting 2021-02-13 19:51:31 +11:00
Jm Casler
b239b4dc57 Merge pull request #686 from mc-hamster/master
Finished and partial work
2021-02-12 19:07:13 -08:00
Jm
19db5ba421 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-12 18:53:08 -08:00
Jm
e225af28dc Disable plugins 2021-02-12 18:52:31 -08:00
Jm Casler
eecf89a9c0 Merge pull request #68 from meshtastic/master
from main to my fork
2021-02-12 18:49:39 -08:00
Jm
c9b1ee532d Update deviceonly.pb.h 2021-02-12 18:49:24 -08:00
Jm
8c27baae84 Update platformio.ini 2021-02-12 18:48:18 -08:00
Kevin Hester
8c225a3c65 disable lora while updating, show "Updating" on oled screen 2021-02-12 13:48:12 +08:00
Jm
b29bcbbd41 #682 Exposing the actual radio center frequency to /static/report 2021-02-09 21:59:00 -08:00
Jm
ca8a0ca8d2 update rangetest 2021-02-07 19:20:29 -08:00
Jm
cb541d75a9 Update radio-settings.md with note of coverage. 2021-02-07 13:19:52 -08:00
Jm Casler
4ee01acb40 Change where the location information is taken from. 2021-02-07 09:31:29 -08:00
Jm
d678c48884 work on rangetestplugin and storeforwardplugin
done for the night.
2021-02-06 23:29:18 -08:00
Jm
9f9f02fc6f Reverting platform.ini back to the way it was. 2021-02-06 21:38:54 -08:00
Jm Casler
abf135abce Merge pull request #66 from meshtastic/master
mc-hamster/meshtastic-device <- meshtastic/meshtastic-device
2021-02-06 19:56:44 -08:00
Jm
22af1b551a Add note about antenna gain. 2021-02-06 10:06:20 -08:00
Jm
c696d226b2 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-06 10:04:13 -08:00
Jm
9035a06b4a Add link budget to radio-settings.md 2021-02-06 10:02:23 -08:00
Jm Casler
056940a4ad Documentation 2021-02-06 09:13:49 -08:00
Jm
82db1f1db6 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-03 08:10:15 -08:00
Jm
f46059ec4c update to range test plugin 2021-02-03 08:10:13 -08:00
Jm
0c71de4e59 Update for rangetest plugin 2021-02-03 08:09:59 -08:00
Jm Casler
0fa654e53a update radio-settings.md 2021-02-03 07:01:35 -08:00
Jm Casler
45c17659cc radio-settings.md - add note about TCXO stability 2021-02-03 01:04:23 -08:00
Jm Casler
b901f8d9ae Update to radio-settings.md 2021-02-03 00:15:41 -08:00
Jm Casler
9c60a7966f Update radio-settings.md 2021-02-03 00:01:52 -08:00
Jm Casler
6d66a53f8d Another update to radio-settings.md 2021-02-02 23:59:34 -08:00
Jm Casler
324627482a Update radio-settings.md 2021-02-02 23:57:25 -08:00
Jm Casler
0c6c189028 Update to radio-settings.md 2021-02-02 23:01:05 -08:00
Jm Casler
8a68ae0d04 Update radio-settings.md 2021-02-02 22:47:16 -08:00
Jm Casler
5661e5dad6 Update radio-settings.md 2021-02-02 22:43:24 -08:00
Jm
e9affb50d2 #674 add support for lora32 v1.3 2021-02-02 17:34:50 -08:00
Jm Casler
c00173dbd2 partial work 2021-01-31 18:20:08 -08:00
Jm Casler
e8c6fccd63 #671 Range Test Plugin
Initial work for Range Test Plugin
2021-01-31 09:12:36 -08:00
Jm Casler
487b8c6e9e #668 Initial work for Store & Forward Plugin 2021-01-31 09:12:01 -08:00
Jm
b2481d1450 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-30 19:42:08 -08:00
Jm
242bcc8353 Update documentation location to the main mesthastic repo 2021-01-30 09:52:21 -08:00
28 changed files with 799 additions and 106 deletions

View File

@@ -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

View 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
*

View File

@@ -1,6 +0,0 @@
# About
# Running notes

View File

@@ -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

Submodule proto updated: b1aed06442...0cadaed395

View File

@@ -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,

View File

@@ -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"

View File

@@ -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
}
}

View File

@@ -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)
{
@@ -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();

View File

@@ -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();

View File

@@ -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();
@@ -178,18 +160,6 @@ 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_payloadVariant == MeshPacket_decoded_tag && p->decoded.which_payloadVariant == 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);
}
@@ -221,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);
@@ -244,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
@@ -254,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;
}

View File

@@ -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.

View File

@@ -212,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
*/
@@ -264,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);
}
/**

View File

@@ -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.
@@ -136,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).
@@ -160,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; }

View File

@@ -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,6 +93,11 @@ 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);
@@ -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,7 +123,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
return res;
#else
packetPool.release(p);
return ERRNO_UNKNOWN;
return ERRNO_DISABLED;
#endif
}
@@ -133,17 +137,17 @@ bool RadioLibInterface::canSleep()
}
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) {
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
{
auto p = txQueue.remove(from, id);
if(p)
if (p)
packetPool.release(p); // free the packet we just removed
bool result = (p != NULL);
DEBUG_MSG("cancelSending id=0x%x, removed=%d", id, result);
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
@@ -242,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) {
@@ -277,7 +281,7 @@ void RadioLibInterface::handleReceiveInterrupt()
addReceiveMetadata(mp);
mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t) payloadLen) <= sizeof(mp->encrypted.bytes));
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
@@ -285,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);
}
@@ -295,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);
}
}

View File

@@ -86,4 +86,4 @@ extern const pb_msgdesc_t DeviceState_msg;
} /* extern "C" */
#endif
#endif
#endif

View File

@@ -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("}");
}

View File

@@ -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

View File

@@ -29,7 +29,7 @@ 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)
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();
@@ -48,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;
}

View File

@@ -4,17 +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
*/
@@ -30,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;

View File

@@ -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
}

View File

@@ -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,14 +39,25 @@ 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)
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();
@@ -50,3 +69,21 @@ void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
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
}

View File

@@ -1,20 +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
*/
@@ -31,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;

View 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
}

View 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;

View 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
}

View 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;

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 1
build = 46
build = 47