Compare commits

...

18 Commits
1.2.4 ... 1.2.6

Author SHA1 Message Date
Kevin Hester
96c4286e7d Merge pull request #733 from geeksville/dev1.2
1.2.6
2021-03-07 10:00:00 +08:00
Kevin Hester
f320ecbde8 1.2.6 2021-03-07 09:51:51 +08:00
Kevin Hester
d014ae0bff fix ls_sleeps communication to device clients 2021-03-07 09:51:17 +08:00
Kevin Hester
12a7934ca1 add RU 2021-03-07 09:34:35 +08:00
Kevin Hester
64bc791e48 fix docs 2021-03-07 09:34:29 +08:00
Kevin Hester
1f33506962 Add RU region 2021-03-06 21:10:36 +08:00
Kevin Hester
ba9a94d026 fix is_low_power detection 2021-03-06 18:00:20 +08:00
Kevin Hester
6f13966d19 fix missing acks for broadcasts 2021-03-06 17:48:35 +08:00
Kevin Hester
96cfad4e57 less logspam 2021-03-06 14:52:26 +08:00
Kevin Hester
a26ebb1b69 Merge pull request #732 from geeksville/dev1.2
Dev1.2 - fix lora message rx
2021-03-06 14:31:59 +08:00
Kevin Hester
7a764efc10 1.2.5 2021-03-06 14:30:53 +08:00
Kevin Hester
49b1f4c5af oops - fix failed text message rx 2021-03-06 14:21:20 +08:00
Kevin Hester
fbe56531d2 Merge remote-tracking branch 'root/master' into dev1.2 2021-03-06 11:20:08 +08:00
Kevin Hester
aa6b29a4b5 fix from address on naks 2021-03-06 11:19:52 +08:00
Kevin Hester
c88b9732eb REALLY IMPORTANT: fix bug with retransmissions not happening 2021-03-06 11:13:33 +08:00
Kevin Hester
2c29e8b179 make nodeinfo & position plugins optional 2021-03-06 10:36:30 +08:00
Kevin Hester
d2d6b8e12f fix log formatting 2021-03-06 10:27:48 +08:00
Kevin Hester
badfaa8545 make error message clearer for packets that are too big 2021-03-06 10:27:31 +08:00
19 changed files with 140 additions and 59 deletions

View File

@@ -34,8 +34,8 @@ You probably don't care about this section - skip to the next one.
* DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
* DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
* fix 1.1.50 android debug panel display
* test android channel setting
* release to users
* DONE test android channel setting
* DONE release to users
* DONE warn in android app about unset regions
* DONE use set-channel from android
* DONE add gui in android app for setting region

2
proto

Submodule proto updated: ac4f53ed8c...7c025b9a4d

View File

@@ -178,10 +178,11 @@ void PowerFSM_setup()
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
/* To determine if we're externally powered, assumptions
1) If we're powered up and there's no battery, we must be getting power externally.
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
2) If we detect USB power from the power management chip, we must be getting power externally.
*/
bool hasPower = (powerStatus && !powerStatus->getHasBattery()) || (!isLowPower && powerStatus && powerStatus->getHasUSB());
bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");

View File

@@ -54,7 +54,7 @@ class ESP32CryptoEngine : public CryptoEngine
static uint8_t scratch[MAX_BLOCKSIZE];
size_t nc_off = 0;
// DEBUG_MSG("ESP32 encrypt!\n");
// DEBUG_MSG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetNum, numBytes);
initNonce(fromNode, packetNum);
assert(numBytes <= MAX_BLOCKSIZE);
memcpy(scratch, bytes, numBytes);

View File

@@ -275,10 +275,11 @@ const char *Channels::getPrimaryName()
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
{
if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
DEBUG_MSG("Skipping channel %d due to invalid hash/index\n", chIndex);
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex), channelHash);
return false;
}
else {
DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
setCrypto(chIndex);
return true;
}

View File

@@ -4,6 +4,10 @@
void CryptoEngine::setKey(const CryptoKey &k)
{
DEBUG_MSG("Installing AES%d key!\n", k.length * 8);
/* for(uint8_t i = 0; i < k.length; i++)
DEBUG_MSG("%02x ", k.bytes[i]);
DEBUG_MSG("\n"); */
key = k;
}

View File

@@ -114,6 +114,7 @@ bool MeshService::reloadConfig()
void MeshService::reloadOwner()
{
assert(nodeInfoPlugin);
if(nodeInfoPlugin)
nodeInfoPlugin->sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -170,13 +171,19 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
assert(positionPlugin && nodeInfoPlugin);
if (node->has_position)
if (node->has_position) {
if(positionPlugin) {
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
positionPlugin->sendOurPosition(dest, wantReplies);
else
}
}
else {
if(nodeInfoPlugin) {
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
}
}
NodeInfo *MeshService::refreshMyNodeInfo()
{

View File

@@ -179,9 +179,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// Do we have a message from the mesh?
if (fromRadioScratch.which_payloadVariant != 0) {
// Encapsulate as a FromRadio packet
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);
// DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payloadVariant, numbytes);
return numbytes;
}

View File

@@ -1,16 +1,16 @@
#include "configuration.h"
#include "RadioInterface.h"
#include "Channels.h"
#include "MeshRadio.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "assert.h"
#include "configuration.h"
#include "Router.h"
#include "sleep.h"
#include <assert.h>
#include <pb_decode.h>
#include <pb_encode.h>
#include "Channels.h"
#define RDEF(name, freq, spacing, num_ch, power_limit) \
{ \
@@ -25,9 +25,27 @@ const RegionInfo regions[] = {
RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel
// freq. (921.9f is for download, others are for uplink)
RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz)
RDEF(RU, 868.9f, 0.2f, 2, 20), // See notes below
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
};
/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2):
According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018) https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1
We have 3 options for 868 MHz:
864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports.
866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports
868,7 - 869,2 MHz ERP 100mW, Duty Cycle 10% or LBT, no resctrictions
and according to RP2-1.0.2 LoRaWAN® Regional Parameters RP2-1.0.2 LoRaWAN® Regional Parameters - LoRa Alliance®
I propose to use following meshtastic bandplan:
1 channel - central frequency 868.9MHz 125kHz band
Protective band - 75kHz
2 channel - central frequency 869.1MHz 125kHz band
RDEF(RU, 868.9f, 0.2f, 2, 20)
*/
const RegionInfo *myRegion;
void initRegion()
@@ -119,8 +137,8 @@ uint32_t RadioInterface::getTxDelayMsec()
void printPacket(const char *prefix, const MeshPacket *p)
{
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
p->hop_limit, p->channel);
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
p->want_ack, p->hop_limit, p->channel);
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
auto &s = p->decoded;
@@ -332,6 +350,10 @@ void RadioInterface::deliverToReceiver(MeshPacket *p)
{
assert(rxDest);
assert(rxDest->enqueue(p, 0)); // NOWAIT - fixme, if queue is full, delete older messages
// Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME
if (router)
router->setReceivedMessage();
}
/***

View File

@@ -1,8 +1,8 @@
#include "ReliableRouter.h"
#include "MeshPlugin.h"
#include "MeshTypes.h"
#include "configuration.h"
#include "mesh-pb-constants.h"
#include "MeshPlugin.h"
// ReliableRouter::ReliableRouter() {}
@@ -35,8 +35,9 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
// the original sending process.
if (stopRetransmission(getFrom(p), p->id)) {
DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n");
if(p->want_ack)
DEBUG_MSG("generating implicit ack\n");
// NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be
// marked as wantAck
sendAckNak(Routing_Error_NONE, getFrom(p), p->id);
}
}
@@ -136,8 +137,9 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
auto id = GlobalPacketId(p);
auto rec = PendingPacket(p);
setNextTx(&rec);
stopRetransmission(getFrom(p), p->id);
setNextTx(&rec);
pending[id] = rec;
return &pending[id];
@@ -157,18 +159,21 @@ int32_t ReliableRouter::doRetransmissions()
++nextIt; // we use this odd pattern because we might be deleting it...
auto &p = it->second;
bool stillValid = true; // assume we'll keep this record around
// FIXME, handle 51 day rolloever here!!!
if (p.nextTxMsec <= now) {
if (p.numRetransmissions == 0) {
DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\n", p.packet->from, p.packet->to,
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
p.packet->id);
sendAckNak(Routing_Error_MAX_RETRANSMIT, p.packet->from, p.packet->id);
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id);
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which
// allows the DSR version to still be able to look at the PendingPacket
stopRetransmission(it->first);
stillValid = false; // just deleted it
} else {
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=%d, tries left=%d\n", p.packet->from, p.packet->to,
p.packet->id, p.numRetransmissions);
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
p.packet->to, p.packet->id, p.numRetransmissions);
// Note: we call the superclass version because we don't want to have our version of send() add a new
// retransmission record
@@ -178,8 +183,10 @@ int32_t ReliableRouter::doRetransmissions()
--p.numRetransmissions;
setNextTx(&p);
}
} else {
// Not yet time
}
if (stillValid) {
// Update our desired sleep delay
int32_t t = p.nextTxMsec - now;
d = min(t, d);
@@ -188,3 +195,13 @@ int32_t ReliableRouter::doRetransmissions()
return d;
}
void ReliableRouter::setNextTx(PendingPacket *pending)
{
assert(iface);
auto d = iface->getRetransmissionMsec(pending->packet);
pending->nextTxMsec = millis() + d;
DEBUG_MSG("Setting next retransmission in %u msecs: ", d);
printPacket("", pending->packet);
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
}

View File

@@ -125,7 +125,5 @@ class ReliableRouter : public FloodingRouter
*/
int32_t doRetransmissions();
void setNextTx(PendingPacket *pending) {
assert(iface);
pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); }
void setNextTx(PendingPacket *pending);
};

View File

@@ -115,12 +115,17 @@ void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
packetPool.release(p);
}
void Router::setReceivedMessage() {
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
}
ErrorCode Router::sendLocal(MeshPacket *p)
{
// No need to deliver externally if the destination is the local node
if (p->to == nodeDB.getNodeNum()) {
printPacket("Enqueuing local", p);
fromRadioQueue.enqueue(p);
setReceivedMessage();
return ERRNO_OK;
} else if (!iface) {
// We must be sending to remote nodes also, fail if no interface found
@@ -138,6 +143,13 @@ ErrorCode Router::sendLocal(MeshPacket *p)
}
}
void printBytes(const char *label, const uint8_t *p, size_t numbytes) {
DEBUG_MSG("%s: ", label);
for(size_t i = 0; i < numbytes; i++)
DEBUG_MSG("%02x ", p[i]);
DEBUG_MSG("\n");
}
/**
* Send a packet on a suitable interface. This routine will
* later free() the packet to pool. This routine is not allowed to stall.
@@ -168,6 +180,8 @@ ErrorCode Router::send(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
// printPacket("pre encrypt", p); // portnum valid here
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
if (numbytes > MAX_RHPACKETLEN) {
@@ -175,6 +189,8 @@ ErrorCode Router::send(MeshPacket *p)
return ERRNO_TOO_LARGE;
}
//printBytes("plaintext", bytes, numbytes);
auto hash = channels.setActiveByIndex(p->channel);
if (hash < 0) {
// No suitable channel could be found for sending
@@ -184,7 +200,7 @@ ErrorCode Router::send(MeshPacket *p)
// Now that we are encrypting the packet channel should be the hash (no longer the index)
p->channel = hash;
crypto->encrypt(p->from, p->id, numbytes, bytes);
crypto->encrypt(getFrom(p), p->id, numbytes, bytes);
// Copy back into the packet and set the variant type
memcpy(p->encrypted.bytes, bytes, numbytes);
@@ -225,20 +241,26 @@ bool Router::perhapsDecode(MeshPacket *p)
if (channels.decryptForHash(chIndex, p->channel)) {
// Try to decrypt the packet if we can
static uint8_t bytes[MAX_RHPACKETLEN];
size_t rawSize = p->encrypted.size;
assert(rawSize <= sizeof(bytes));
memcpy(bytes, p->encrypted.bytes,
p->encrypted
.size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
crypto->decrypt(p->from, p->id, p->encrypted.size, bytes);
rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
crypto->decrypt(p->from, p->id, rawSize, bytes);
//printBytes("plaintext", bytes, p->encrypted.size);
// Take those raw bytes and convert them back into a well structured protobuf we can understand
memset(&p->decoded, 0, sizeof(p->decoded));
if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) {
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n");
} else {
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
} else if(p->decoded.portnum == PortNum_UNKNOWN_APP) {
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
}
else {
// parsing was successful
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
p->channel = chIndex; // change to store the index instead of the hash
// printPacket("decoded message", p);
p->which_payloadVariant = MeshPacket_decoded_tag;
printPacket("decoded message", p);
return true;
}
}
@@ -264,10 +286,9 @@ void Router::handleReceived(MeshPacket *p)
// Take those raw bytes and convert them back into a well structured protobuf we can understand
bool decoded = perhapsDecode(p);
printPacket("handleReceived", p);
DEBUG_MSG("decoded=%d\n", decoded);
if (decoded) {
// parsing was successful, queue for our recipient
printPacket("handleReceived", p);
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
// sniffReceived(p);

View File

@@ -63,6 +63,11 @@ class Router : protected concurrency::OSThread
* @return our local nodenum */
NodeNum getNodeNum();
/** Wake up the router thread ASAP, because we just queued a message for it.
* FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue'
*/
void setReceivedMessage();
protected:
friend class RoutingPlugin;

View File

@@ -19,7 +19,8 @@ typedef enum _RegionCode {
RegionCode_JP = 5,
RegionCode_ANZ = 6,
RegionCode_KR = 7,
RegionCode_TW = 8
RegionCode_TW = 8,
RegionCode_RU = 9
} RegionCode;
typedef enum _ChargeCurrent {
@@ -123,8 +124,8 @@ typedef struct _RadioConfig {
/* Helper constants for enums */
#define _RegionCode_MIN RegionCode_Unset
#define _RegionCode_MAX RegionCode_TW
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
#define _RegionCode_MAX RegionCode_RU
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_RU+1))
#define _ChargeCurrent_MIN ChargeCurrent_MAUnset
#define _ChargeCurrent_MAX ChargeCurrent_MA1320

View File

@@ -18,8 +18,8 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc
pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize);
if (!pb_encode(&stream, fields, src_struct)) {
DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
assert(0); // FIXME - panic
DEBUG_MSG("Panic: can't encode protobuf %s, did you make a field too large?\n", PB_GET_ERROR(&stream));
assert(0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options
} else {
return stream.bytes_written;
}

View File

@@ -24,6 +24,12 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req)
// We create the reply here
AdminMessage r = AdminMessage_init_default;
r.get_radio_response = devicestate.radio;
// 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).
r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
r.which_variant = AdminMessage_get_radio_response_tag;
reply = allocDataProtobuf(r);
}

View File

@@ -65,8 +65,7 @@ int32_t NodeInfoPlugin::runOnce()
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)
sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
return getPref_position_broadcast_secs() * 1000;
}

View File

@@ -8,7 +8,7 @@ TextMessagePlugin *textMessagePlugin;
bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
{
auto &p = mp.decoded;
DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
DEBUG_MSG("Received text msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
// We only store/display messages destined for us.
// Keep a copy of the most recent text message.

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 2
build = 4
build = 6