Merge pull request #68 from meshtastic/master

from main to my fork
This commit is contained in:
Jm Casler 2021-02-12 18:49:39 -08:00 committed by GitHub
commit eecf89a9c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 324 additions and 119 deletions

2
proto

@ -1 +1 @@
Subproject commit 106f4bfdebe277ab0b86d2b8c950ab78a35b0654 Subproject commit b1aed06442025624841b2288fac273d9bc41c438

View File

@ -201,7 +201,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// the max length of this buffer is much longer than we can possibly print // the max length of this buffer is much longer than we can possibly print
static char tempBuf[96]; 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); snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf); display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf);

View File

@ -72,7 +72,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
addRoute(p->from, p->from, 0); // We are adjacent with zero hops 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: case SubPacket_route_request_tag:
// Handle route discovery packets (will be a broadcast message) // Handle route discovery packets (will be a broadcast message)
// FIXME - always start request with the senders nodenum // 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 // handle naks - convert them to route error packets
// All naks are generated locally, because we failed resending the packet too many times // 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) { if (nakId) {
auto pending = findPendingPacket(p->to, 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 if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore

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

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

View File

@ -169,6 +169,11 @@ 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) void MeshService::sendToMesh(MeshPacket *p)
{ {
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...) nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
@ -176,7 +181,7 @@ void MeshService::sendToMesh(MeshPacket *p)
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other // 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 // 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. // devices can get time.
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag && if (p->which_payloadVariant == MeshPacket_decoded_tag && p->decoded.which_payloadVariant == SubPacket_position_tag &&
p->decoded.position.time) { p->decoded.position.time) {
if (getRTCQuality() < RTCQualityGPS) { if (getRTCQuality() < RTCQualityGPS) {
DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time); DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);

View File

@ -79,6 +79,9 @@ class MeshService
/// cache /// cache
void sendToMesh(MeshPacket *p); 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 /// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo(); NodeInfo *refreshMyNodeInfo();

View File

@ -265,16 +265,15 @@ void NodeDB::installDefaultDeviceState()
// Init our blank owner info to reasonable defaults // Init our blank owner info to reasonable defaults
getMacAddr(ourMacAddr); 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 // Set default owner name
pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid pickNewNodeNum(); // based on macaddr now
// owner.short_name now
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]); sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff)); 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 // Restore region if possible
if (oldRegionCode != RegionCode_Unset) if (oldRegionCode != RegionCode_Unset)
radioConfig.preferences.region = oldRegionCode; 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 /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void NodeDB::updateFrom(const MeshPacket &mp) 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; const SubPacket &p = mp.decoded;
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time); 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. 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: { case SubPacket_position_tag: {
// handle a legacy position packet // handle a legacy position packet
DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from); 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 // Print error to screen and serial port
String lcd = String("Critical error ") + code + "!\n"; String lcd = String("Critical error ") + code + "!\n";
screen->print(lcd.c_str()); 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 // Record error to DB
myNodeInfo.error_code = code; myNodeInfo.error_code = code;

View File

@ -59,15 +59,15 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
// return (lastContactMsec != 0) && // return (lastContactMsec != 0) &&
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) { if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
switch (toRadioScratch.which_variant) { switch (toRadioScratch.which_payloadVariant) {
case ToRadio_packet_tag: { case ToRadio_packet_tag: {
MeshPacket &p = toRadioScratch.variant.packet; MeshPacket &p = toRadioScratch.packet;
printPacket("PACKET FROM PHONE", &p); printPacket("PACKET FROM PHONE", &p);
service.handleToRadio(p); service.handleToRadio(p);
break; break;
} }
case ToRadio_want_config_id_tag: 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); DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
state = STATE_SEND_MY_INFO; state = STATE_SEND_MY_INFO;
@ -79,12 +79,12 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
case ToRadio_set_owner_tag: case ToRadio_set_owner_tag:
DEBUG_MSG("Client is setting owner\n"); DEBUG_MSG("Client is setting owner\n");
handleSetOwner(toRadioScratch.variant.set_owner); handleSetOwner(toRadioScratch.set_owner);
break; break;
case ToRadio_set_radio_tag: case ToRadio_set_radio_tag:
DEBUG_MSG("Client is setting radio\n"); DEBUG_MSG("Client is setting radio\n");
handleSetRadio(toRadioScratch.variant.set_radio); handleSetRadio(toRadioScratch.set_radio);
break; break;
default: default:
@ -131,22 +131,22 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled) myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled)
? true ? true
: (gps && gps->isConnected()); // Update with latest GPS connect info : (gps && gps->isConnected()); // Update with latest GPS connect info
fromRadioScratch.which_variant = FromRadio_my_info_tag; fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
fromRadioScratch.variant.my_info = myNodeInfo; fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_RADIO; state = STATE_SEND_RADIO;
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon. service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
break; break;
case STATE_SEND_RADIO: 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. // 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 // 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). // 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; state = STATE_SEND_NODEINFO;
break; break;
@ -158,8 +158,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
if (info) { if (info) {
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id, DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
info->user.long_name); info->user.long_name);
fromRadioScratch.which_variant = FromRadio_node_info_tag; fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
fromRadioScratch.variant.node_info = *info; fromRadioScratch.node_info = *info;
// Stay in current state until done sending nodeinfos // Stay in current state until done sending nodeinfos
} else { } else {
DEBUG_MSG("Done sending nodeinfos\n"); DEBUG_MSG("Done sending nodeinfos\n");
@ -171,8 +171,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
} }
case STATE_SEND_COMPLETE_ID: case STATE_SEND_COMPLETE_ID:
fromRadioScratch.which_variant = FromRadio_config_complete_id_tag; fromRadioScratch.which_payloadVariant = FromRadio_config_complete_id_tag;
fromRadioScratch.variant.config_complete_id = config_nonce; fromRadioScratch.config_complete_id = config_nonce;
config_nonce = 0; config_nonce = 0;
state = STATE_SEND_PACKETS; state = STATE_SEND_PACKETS;
break; break;
@ -185,8 +185,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
printPacket("phone downloaded packet", packetForPhone); printPacket("phone downloaded packet", packetForPhone);
// Encapsulate as a FromRadio packet // Encapsulate as a FromRadio packet
fromRadioScratch.which_variant = FromRadio_packet_tag; fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
fromRadioScratch.variant.packet = *packetForPhone; fromRadioScratch.packet = *packetForPhone;
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
packetForPhone = NULL; packetForPhone = NULL;
@ -198,9 +198,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
} }
// Do we have a message from the mesh? // Do we have a message from the mesh?
if (fromRadioScratch.which_variant != 0) { if (fromRadioScratch.which_payloadVariant != 0) {
// Encapsulate as a FromRadio packet // 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); size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
DEBUG_MSG(", %d bytes\n", numbytes); DEBUG_MSG(", %d bytes\n", numbytes);
return numbytes; return numbytes;

View File

@ -83,7 +83,7 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl)
uint32_t RadioInterface::getPacketTime(MeshPacket *p) 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); uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
return getPacketTime(pl); 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, 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); p->hop_limit);
if (p->which_payload == MeshPacket_decoded_tag) { if (p->which_payloadVariant == MeshPacket_decoded_tag) {
auto &s = p->decoded; auto &s = p->decoded;
switch (s.which_payload) { switch (s.which_payloadVariant) {
case SubPacket_data_tag: case SubPacket_data_tag:
DEBUG_MSG(" Portnum=%d", s.data.portnum); DEBUG_MSG(" Portnum=%d", s.data.portnum);
break; break;
@ -135,7 +135,7 @@ void printPacket(const char *prefix, const MeshPacket *p)
DEBUG_MSG(" Payload:None"); DEBUG_MSG(" Payload:None");
break; break;
default: default:
DEBUG_MSG(" Payload:%d", s.which_payload); DEBUG_MSG(" Payload:%d", s.which_payloadVariant);
break; break;
} }
if (s.want_response) if (s.want_response)
@ -147,10 +147,10 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (s.dest != 0) if (s.dest != 0)
DEBUG_MSG(" dest=%08x", s.dest); DEBUG_MSG(" dest=%08x", s.dest);
if (s.which_ack == SubPacket_success_id_tag) if (s.which_ackVariant == SubPacket_success_id_tag)
DEBUG_MSG(" successId=%08x", s.ack.success_id); DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
else if (s.which_ack == SubPacket_fail_id_tag) else if (s.which_ackVariant == SubPacket_fail_id_tag)
DEBUG_MSG(" failId=%08x", s.ack.fail_id); DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id);
} else { } else {
DEBUG_MSG(" encrypted"); DEBUG_MSG(" encrypted");
} }
@ -161,6 +161,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (p->rx_snr != 0.0) { if (p->rx_snr != 0.0) {
DEBUG_MSG(" rxSNR=%g", p->rx_snr); DEBUG_MSG(" rxSNR=%g", p->rx_snr);
} }
if(p->priority != 0)
DEBUG_MSG(" priority=%d", p->priority);
DEBUG_MSG(")\n"); DEBUG_MSG(")\n");
} }
@ -348,7 +351,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
assert(!sendingPacket); assert(!sendingPacket);
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad()); // 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(); lastTxStart = millis();

View File

@ -105,6 +105,9 @@ class RadioInterface
*/ */
virtual ErrorCode send(MeshPacket *p) = 0; 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 // methods from radiohead
/// Initialise the Driver transport hardware and software. /// Initialise the Driver transport hardware and software.

View File

@ -100,7 +100,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
uint32_t xmitMsec = getPacketTime(p); uint32_t xmitMsec = getPacketTime(p);
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad); 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 if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
packetPool.release(p); packetPool.release(p);
@ -125,13 +125,25 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
bool RadioLibInterface::canSleep() bool RadioLibInterface::canSleep()
{ {
bool res = txQueue.isEmpty(); bool res = txQueue.empty();
if (!res) // only print debug messages if we are vetoing sleep if (!res) // only print debug messages if we are vetoing sleep
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res); DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
return 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", id, result);
return result;
}
/** radio helper thread callback. /** radio helper thread callback.
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
@ -165,12 +177,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 // 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? // 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()) { if (!canSendImmediately()) {
startTransmitTimer(); // try again in a little while startTransmitTimer(); // try again in a little while
} else { } else {
// Send any outgoing packets we have ready // Send any outgoing packets we have ready
MeshPacket *txp = txQueue.dequeuePtr(0); MeshPacket *txp = txQueue.dequeue();
assert(txp); assert(txp);
startSend(txp); startSend(txp);
} }
@ -186,7 +198,7 @@ void RadioLibInterface::onNotify(uint32_t notification)
void RadioLibInterface::startTransmitTimer(bool withDelay) void RadioLibInterface::startTransmitTimer(bool withDelay)
{ {
// If we have work to do and the timer wasn't already scheduled, schedule it now // 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(); uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
// DEBUG_MSG("xmit timer %d\n", delay); // DEBUG_MSG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
@ -264,7 +276,7 @@ void RadioLibInterface::handleReceiveInterrupt()
addReceiveMetadata(mp); addReceiveMetadata(mp);
mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point 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); memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen; mp->encrypted.size = payloadLen;

View File

@ -2,6 +2,7 @@
#include "../concurrency/OSThread.h" #include "../concurrency/OSThread.h"
#include "RadioInterface.h" #include "RadioInterface.h"
#include "MeshPacketQueue.h"
#ifdef CubeCell_BoardPlus #ifdef CubeCell_BoardPlus
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
@ -74,7 +75,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/ */
uint32_t rxBad = 0, rxGood = 0, txGood = 0; uint32_t rxBad = 0, rxGood = 0, txGood = 0;
PointerQueue<MeshPacket> txQueue = PointerQueue<MeshPacket>(MAX_TX_QUEUE); MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
protected: protected:
@ -136,6 +137,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/ */
virtual bool isActivelyReceiving() = 0; 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: private:
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing /** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
* the transmit * the transmit

View File

@ -65,8 +65,8 @@ void ReliableRouter::sniffReceived(const MeshPacket *p)
// If the payload is valid, look for ack/nak // 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 ackId = p->decoded.which_ackVariant == SubPacket_success_id_tag ? p->decoded.ackVariant.success_id : 0;
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;
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if (ackId || nakId) { if (ackId || nakId) {

View File

@ -88,7 +88,7 @@ MeshPacket *Router::allocForSending()
{ {
MeshPacket *p = packetPool.allocZeroed(); 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->from = nodeDB.getNodeNum();
p->to = NODENUM_BROADCAST; p->to = NODENUM_BROADCAST;
p->hop_limit = HOP_RELIABLE; 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); DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
if (!err) { if (!err) {
p->decoded.ack.success_id = idFrom; p->decoded.ackVariant.success_id = idFrom;
p->decoded.which_ack = SubPacket_success_id_tag; p->decoded.which_ackVariant = SubPacket_success_id_tag;
} else { } else {
p->decoded.ack.fail_id = idFrom; p->decoded.ackVariant.fail_id = idFrom;
p->decoded.which_ack = SubPacket_fail_id_tag; p->decoded.which_ackVariant = SubPacket_fail_id_tag;
// Also send back the error reason // 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->decoded.error_reason = err;
} }
p->priority = MeshPacket_Priority_ACK;
sendLocal(p); // we sometimes send directly to the local node sendLocal(p); // we sometimes send directly to the local node
} }
ErrorCode Router::sendLocal(MeshPacket *p) ErrorCode Router::sendLocal(MeshPacket *p)
{ {
// No need to deliver externally if the destination is the local node // 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 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( assert(
!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with 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) // 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 || assert(p->which_payloadVariant == MeshPacket_encrypted_tag ||
p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now p->which_payloadVariant == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
// First convert from protobufs to raw bytes // 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 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); 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 // Copy back into the packet and set the variant type
memcpy(p->encrypted.bytes, bytes, numbytes); memcpy(p->encrypted.bytes, bytes, numbytes);
p->encrypted.size = 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) 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 * 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) * 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) 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 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 // FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without
// being able to decrypt their data. // being able to decrypt their data.
@ -230,7 +240,7 @@ bool Router::perhapsDecode(MeshPacket *p)
return false; return false;
} else { } else {
// parsing was successful // parsing was successful
p->which_payload = MeshPacket_decoded_tag; p->which_payloadVariant = MeshPacket_decoded_tag;
return true; return true;
} }
} }

View File

@ -55,7 +55,12 @@ class Router : protected concurrency::OSThread
*/ */
ErrorCode sendLocal(MeshPacket *p); 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(); MeshPacket *allocForSending();
/** /**

View File

@ -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) // Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = router->allocForSending(); MeshPacket *p = router->allocForSending();
p->decoded.which_payload = SubPacket_data_tag; p->decoded.which_payloadVariant = SubPacket_data_tag;
p->decoded.data.portnum = ourPortNum; p->decoded.data.portnum = ourPortNum;
return p; return p;

View File

@ -84,8 +84,8 @@ void StreamAPI::emitRebooted()
{ {
// In case we send a FromRadio packet // In case we send a FromRadio packet
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
fromRadioScratch.which_variant = FromRadio_rebooted_tag; fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
fromRadioScratch.variant.rebooted = true; fromRadioScratch.rebooted = true;
DEBUG_MSG("Emitting reboot packet for serial shell\n"); DEBUG_MSG("Emitting reboot packet for serial shell\n");
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch)); emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));

View File

@ -58,3 +58,4 @@ PB_BIND(ToRadio, ToRadio, 2)

View File

@ -83,6 +83,16 @@ typedef enum _CriticalErrorCode {
CriticalErrorCode_TransmitFailed = 8 CriticalErrorCode_TransmitFailed = 8
} CriticalErrorCode; } 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 { typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0, ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1, ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
@ -230,7 +240,7 @@ typedef struct _RadioConfig {
} RadioConfig; } RadioConfig;
typedef struct _SubPacket { typedef struct _SubPacket {
pb_size_t which_payload; pb_size_t which_payloadVariant;
union { union {
Position position; Position position;
Data data; Data data;
@ -242,11 +252,11 @@ typedef struct _SubPacket {
uint32_t original_id; uint32_t original_id;
bool want_response; bool want_response;
uint32_t dest; uint32_t dest;
pb_size_t which_ack; pb_size_t which_ackVariant;
union { union {
uint32_t success_id; uint32_t success_id;
uint32_t fail_id; uint32_t fail_id;
} ack; } ackVariant;
uint32_t source; uint32_t source;
} SubPacket; } SubPacket;
@ -254,7 +264,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
typedef struct _MeshPacket { typedef struct _MeshPacket {
uint32_t from; uint32_t from;
uint32_t to; uint32_t to;
pb_size_t which_payload; pb_size_t which_payloadVariant;
union { union {
SubPacket decoded; SubPacket decoded;
MeshPacket_encrypted_t encrypted; MeshPacket_encrypted_t encrypted;
@ -265,11 +275,12 @@ typedef struct _MeshPacket {
uint32_t rx_time; uint32_t rx_time;
uint32_t hop_limit; uint32_t hop_limit;
bool want_ack; bool want_ack;
MeshPacket_Priority priority;
} MeshPacket; } MeshPacket;
typedef struct _FromRadio { typedef struct _FromRadio {
uint32_t num; uint32_t num;
pb_size_t which_variant; pb_size_t which_payloadVariant;
union { union {
MeshPacket packet; MeshPacket packet;
MyNodeInfo my_info; MyNodeInfo my_info;
@ -279,18 +290,18 @@ typedef struct _FromRadio {
uint32_t config_complete_id; uint32_t config_complete_id;
bool rebooted; bool rebooted;
ChannelSettings channel; ChannelSettings channel;
} variant; };
} FromRadio; } FromRadio;
typedef struct _ToRadio { typedef struct _ToRadio {
pb_size_t which_variant; pb_size_t which_payloadVariant;
union { union {
MeshPacket packet; MeshPacket packet;
uint32_t want_config_id; uint32_t want_config_id;
RadioConfig set_radio; RadioConfig set_radio;
User set_owner; User set_owner;
ChannelSettings set_channel; ChannelSettings set_channel;
} variant; };
} ToRadio; } ToRadio;
@ -323,6 +334,10 @@ typedef struct _ToRadio {
#define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed #define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1)) #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_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096 #define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1)) #define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
@ -342,7 +357,7 @@ extern "C" {
#define User_init_default {"", "", "", {0}} #define User_init_default {"", "", "", {0}}
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 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 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 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_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, 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}
@ -356,7 +371,7 @@ extern "C" {
#define User_init_zero {"", "", "", {0}} #define User_init_zero {"", "", "", {0}}
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 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 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 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_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, 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}
@ -479,6 +494,7 @@ extern "C" {
#define MeshPacket_rx_time_tag 9 #define MeshPacket_rx_time_tag 9
#define MeshPacket_hop_limit_tag 10 #define MeshPacket_hop_limit_tag 10
#define MeshPacket_want_ack_tag 11 #define MeshPacket_want_ack_tag 11
#define MeshPacket_priority_tag 12
#define FromRadio_num_tag 1 #define FromRadio_num_tag 1
#define FromRadio_packet_tag 2 #define FromRadio_packet_tag 2
#define FromRadio_my_info_tag 3 #define FromRadio_my_info_tag 3
@ -524,40 +540,41 @@ X(a, STATIC, REPEATED, INT32, route, 2)
#define RouteDiscovery_DEFAULT NULL #define RouteDiscovery_DEFAULT NULL
#define SubPacket_FIELDLIST(X, a) \ #define SubPacket_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payload,position,position), 1) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,position), 1) \
X(a, STATIC, ONEOF, MESSAGE, (payload,data,data), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,data,data), 3) \
X(a, STATIC, ONEOF, MESSAGE, (payload,user,user), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,user,user), 4) \
X(a, STATIC, ONEOF, MESSAGE, (payload,route_request,route_request), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_request,route_request), 6) \
X(a, STATIC, ONEOF, MESSAGE, (payload,route_reply,route_reply), 7) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_reply,route_reply), 7) \
X(a, STATIC, ONEOF, UENUM, (payload,error_reason,error_reason), 13) \ X(a, STATIC, ONEOF, UENUM, (payloadVariant,error_reason,error_reason), 13) \
X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ X(a, STATIC, SINGULAR, UINT32, original_id, 2) \
X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ X(a, STATIC, SINGULAR, BOOL, want_response, 5) \
X(a, STATIC, SINGULAR, UINT32, dest, 9) \ X(a, STATIC, SINGULAR, UINT32, dest, 9) \
X(a, STATIC, ONEOF, UINT32, (ack,success_id,ack.success_id), 10) \ X(a, STATIC, ONEOF, UINT32, (ackVariant,success_id,ackVariant.success_id), 10) \
X(a, STATIC, ONEOF, UINT32, (ack,fail_id,ack.fail_id), 11) \ X(a, STATIC, ONEOF, UINT32, (ackVariant,fail_id,ackVariant.fail_id), 11) \
X(a, STATIC, SINGULAR, UINT32, source, 12) X(a, STATIC, SINGULAR, UINT32, source, 12)
#define SubPacket_CALLBACK NULL #define SubPacket_CALLBACK NULL
#define SubPacket_DEFAULT NULL #define SubPacket_DEFAULT NULL
#define SubPacket_payload_position_MSGTYPE Position #define SubPacket_payloadVariant_position_MSGTYPE Position
#define SubPacket_payload_data_MSGTYPE Data #define SubPacket_payloadVariant_data_MSGTYPE Data
#define SubPacket_payload_user_MSGTYPE User #define SubPacket_payloadVariant_user_MSGTYPE User
#define SubPacket_payload_route_request_MSGTYPE RouteDiscovery #define SubPacket_payloadVariant_route_request_MSGTYPE RouteDiscovery
#define SubPacket_payload_route_reply_MSGTYPE RouteDiscovery #define SubPacket_payloadVariant_route_reply_MSGTYPE RouteDiscovery
#define MeshPacket_FIELDLIST(X, a) \ #define MeshPacket_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, from, 1) \ X(a, STATIC, SINGULAR, UINT32, from, 1) \
X(a, STATIC, SINGULAR, UINT32, to, 2) \ X(a, STATIC, SINGULAR, UINT32, to, 2) \
X(a, STATIC, ONEOF, MESSAGE, (payload,decoded,decoded), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 3) \
X(a, STATIC, ONEOF, BYTES, (payload,encrypted,encrypted), 8) \ X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 8) \
X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \ X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \
X(a, STATIC, SINGULAR, UINT32, id, 6) \ X(a, STATIC, SINGULAR, UINT32, id, 6) \
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \ X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \
X(a, STATIC, SINGULAR, FIXED32, rx_time, 9) \ X(a, STATIC, SINGULAR, FIXED32, rx_time, 9) \
X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \ 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_CALLBACK NULL
#define MeshPacket_DEFAULT NULL #define MeshPacket_DEFAULT NULL
#define MeshPacket_payload_decoded_MSGTYPE SubPacket #define MeshPacket_payloadVariant_decoded_MSGTYPE SubPacket
#define ChannelSettings_FIELDLIST(X, a) \ #define ChannelSettings_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \ X(a, STATIC, SINGULAR, INT32, tx_power, 1) \
@ -667,35 +684,35 @@ X(a, STATIC, SINGULAR, UENUM, level, 4)
#define FromRadio_FIELDLIST(X, a) \ #define FromRadio_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, num, 1) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \
X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 2) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,my_info,variant.my_info), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \
X(a, STATIC, ONEOF, MESSAGE, (variant,node_info,variant.node_info), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \
X(a, STATIC, ONEOF, MESSAGE, (variant,radio,variant.radio), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,radio,radio), 6) \
X(a, STATIC, ONEOF, MESSAGE, (variant,log_record,variant.log_record), 7) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \
X(a, STATIC, ONEOF, UINT32, (variant,config_complete_id,variant.config_complete_id), 8) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \
X(a, STATIC, ONEOF, BOOL, (variant,rebooted,variant.rebooted), 9) \ X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \
X(a, STATIC, ONEOF, MESSAGE, (variant,channel,variant.channel), 10) X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,channel), 10)
#define FromRadio_CALLBACK NULL #define FromRadio_CALLBACK NULL
#define FromRadio_DEFAULT NULL #define FromRadio_DEFAULT NULL
#define FromRadio_variant_packet_MSGTYPE MeshPacket #define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket
#define FromRadio_variant_my_info_MSGTYPE MyNodeInfo #define FromRadio_payloadVariant_my_info_MSGTYPE MyNodeInfo
#define FromRadio_variant_node_info_MSGTYPE NodeInfo #define FromRadio_payloadVariant_node_info_MSGTYPE NodeInfo
#define FromRadio_variant_radio_MSGTYPE RadioConfig #define FromRadio_payloadVariant_radio_MSGTYPE RadioConfig
#define FromRadio_variant_log_record_MSGTYPE LogRecord #define FromRadio_payloadVariant_log_record_MSGTYPE LogRecord
#define FromRadio_variant_channel_MSGTYPE ChannelSettings #define FromRadio_payloadVariant_channel_MSGTYPE ChannelSettings
#define ToRadio_FIELDLIST(X, a) \ #define ToRadio_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 1) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 1) \
X(a, STATIC, ONEOF, UINT32, (variant,want_config_id,variant.want_config_id), 100) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,variant.set_radio), 101) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,set_radio), 101) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,set_owner), 102) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,variant.set_channel), 103) X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,set_channel), 103)
#define ToRadio_CALLBACK NULL #define ToRadio_CALLBACK NULL
#define ToRadio_DEFAULT NULL #define ToRadio_DEFAULT NULL
#define ToRadio_variant_packet_MSGTYPE MeshPacket #define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket
#define ToRadio_variant_set_radio_MSGTYPE RadioConfig #define ToRadio_payloadVariant_set_radio_MSGTYPE RadioConfig
#define ToRadio_variant_set_owner_MSGTYPE User #define ToRadio_payloadVariant_set_owner_MSGTYPE User
#define ToRadio_variant_set_channel_MSGTYPE ChannelSettings #define ToRadio_payloadVariant_set_channel_MSGTYPE ChannelSettings
extern const pb_msgdesc_t Position_msg; extern const pb_msgdesc_t Position_msg;
extern const pb_msgdesc_t Data_msg; extern const pb_msgdesc_t Data_msg;
@ -734,7 +751,7 @@ extern const pb_msgdesc_t ToRadio_msg;
#define User_size 72 #define User_size 72
#define RouteDiscovery_size 88 #define RouteDiscovery_size 88
#define SubPacket_size 275 #define SubPacket_size 275
#define MeshPacket_size 320 #define MeshPacket_size 322
#define ChannelSettings_size 95 #define ChannelSettings_size 95
#define RadioConfig_size 405 #define RadioConfig_size 405
#define RadioConfig_UserPreferences_size 305 #define RadioConfig_UserPreferences_size 305

View File

@ -20,6 +20,7 @@ typedef enum _PortNum {
PortNum_IP_TUNNEL_APP = 33, PortNum_IP_TUNNEL_APP = 33,
PortNum_SERIAL_APP = 64, PortNum_SERIAL_APP = 64,
PortNum_STORE_FORWARD_APP = 65, PortNum_STORE_FORWARD_APP = 65,
PortNum_RANGE_TEST_APP = 66,
PortNum_PRIVATE_APP = 256, PortNum_PRIVATE_APP = 256,
PortNum_ATAK_FORWARDER = 257 PortNum_ATAK_FORWARDER = 257
} PortNum; } PortNum;

View File

@ -28,9 +28,15 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p)
void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies) 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(); MeshPacket *p = allocReply();
p->to = dest; p->to = dest;
p->decoded.want_response = wantReplies; p->decoded.want_response = wantReplies;
p->priority = MeshPacket_Priority_BACKGROUND;
prevPacketId = p->id;
service.sendToMesh(p); service.sendToMesh(p);
} }

View File

@ -6,6 +6,9 @@
*/ */
class NodeInfoPlugin : public ProtobufPlugin<User> class NodeInfoPlugin : public ProtobufPlugin<User>
{ {
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
PacketId prevPacketId = 0;
public: public:
/** Constructor /** Constructor
* name is for debugging output * name is for debugging output

View File

@ -37,9 +37,15 @@ MeshPacket *PositionPlugin::allocReply()
void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) 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(); MeshPacket *p = allocReply();
p->to = dest; p->to = dest;
p->decoded.want_response = wantReplies; p->decoded.want_response = wantReplies;
p->priority = MeshPacket_Priority_BACKGROUND;
prevPacketId = p->id;
service.sendToMesh(p); service.sendToMesh(p);
} }

View File

@ -6,6 +6,9 @@
*/ */
class PositionPlugin : public ProtobufPlugin<Position> class PositionPlugin : public ProtobufPlugin<Position>
{ {
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
PacketId prevPacketId = 0;
public: public:
/** Constructor /** Constructor
* name is for debugging output * name is for debugging output

View File

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