Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions examples/simple_repeater/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,23 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
return true;
}

bool MyMesh::isNextHopNeighbor(const mesh::Packet* packet) {
#if MAX_NEIGHBOURS
// TODO: check prefs to see if fuzzy pathing is enabled
// TODO: only consider neighbors that have been heard in a configurable amount of time
// TODO: make min SNR configurable
const int8_t min_snr = 0; // *4.f = actual snr value
for (int i = 0; i < MAX_NEIGHBOURS; ++i) {
auto neighbor = &neighbours[i];
if (neighbor->heard_timestamp > 0 && neighbor->snr >= min_snr && neighbor->id.isHashMatch(packet->path, packet->getPathHashSize())) {
return true;
}
}
#endif

return false;
}

const char *MyMesh::getLogDateTime() {
static char tmp[32];
uint32_t now = getRTCClock()->getCurrentTime();
Expand Down Expand Up @@ -480,7 +497,7 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
if (f) {
f.print(getLogDateTime());
f.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d", len,
pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len,
pkt->getPayloadType(), pkt->isRouteDirect() ? (pkt->isRouteFuzzy() ? "Z" : "D") : "F", pkt->payload_len,
(int)_radio->getLastSNR(), (int)_radio->getLastRSSI(), (int)(score * 1000));

if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ ||
Expand All @@ -506,7 +523,7 @@ void MyMesh::logTx(mesh::Packet *pkt, int len) {
if (f) {
f.print(getLogDateTime());
f.printf(": TX, len=%d (type=%d, route=%s, payload_len=%d)", len, pkt->getPayloadType(),
pkt->isRouteDirect() ? "D" : "F", pkt->payload_len);
pkt->isRouteDirect() ? (pkt->isRouteFuzzy() ? "Z" : "D") : "F", pkt->payload_len);

if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ ||
pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
Expand All @@ -525,7 +542,7 @@ void MyMesh::logTxFail(mesh::Packet *pkt, int len) {
if (f) {
f.print(getLogDateTime());
f.printf(": TX FAIL!, len=%d (type=%d, route=%s, payload_len=%d)\n", len, pkt->getPayloadType(),
pkt->isRouteDirect() ? "D" : "F", pkt->payload_len);
pkt->isRouteDirect() ? (pkt->isRouteFuzzy() ? "Z" : "D") : "F", pkt->payload_len);
f.close();
}
}
Expand Down
1 change: 1 addition & 0 deletions examples/simple_repeater/MyMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
}

bool allowPacketForward(const mesh::Packet* packet) override;
bool isNextHopNeighbor(const mesh::Packet* packet) override;
const char* getLogDateTime() override;
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;

Expand Down
6 changes: 3 additions & 3 deletions examples/simple_room_server/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
if (f) {
f.print(getLogDateTime());
f.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d", len,
pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len,
pkt->getPayloadType(), pkt->isRouteDirect() ? (pkt->isRouteFuzzy() ? "Z" : "D") : "F", pkt->payload_len,
(int)_radio->getLastSNR(), (int)_radio->getLastRSSI(), (int)(score * 1000));

if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ ||
Expand All @@ -233,7 +233,7 @@ void MyMesh::logTx(mesh::Packet *pkt, int len) {
if (f) {
f.print(getLogDateTime());
f.printf(": TX, len=%d (type=%d, route=%s, payload_len=%d)", len, pkt->getPayloadType(),
pkt->isRouteDirect() ? "D" : "F", pkt->payload_len);
pkt->isRouteDirect() ? (pkt->isRouteFuzzy() ? "Z" : "D") : "F", pkt->payload_len);

if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ ||
pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
Expand All @@ -251,7 +251,7 @@ void MyMesh::logTxFail(mesh::Packet *pkt, int len) {
if (f) {
f.print(getLogDateTime());
f.printf(": TX FAIL!, len=%d (type=%d, route=%s, payload_len=%d)\n", len, pkt->getPayloadType(),
pkt->isRouteDirect() ? "D" : "F", pkt->payload_len);
pkt->isRouteDirect() ? (pkt->isRouteFuzzy() ? "Z" : "D") : "F", pkt->payload_len);
f.close();
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Dispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ void Dispatcher::checkRecv() {
#if MESH_PACKET_LOGGING
Serial.print(getLogDateTime());
Serial.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d time=%d",
pkt->getRawLength(), pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len,
pkt->getRawLength(), pkt->getPayloadType(), pkt->isRouteDirect() ? (pkt->isRouteFuzzy() ? "Z" : "D") : "F", pkt->payload_len,
(int)pkt->getSNR(), (int)_radio->getLastRSSI(), (int)(score*1000), air_time);

static uint8_t packet_hash[MAX_HASH_SIZE];
Expand Down Expand Up @@ -340,7 +340,7 @@ void Dispatcher::checkSend() {
#if MESH_PACKET_LOGGING
Serial.print(getLogDateTime());
Serial.printf(": TX, len=%d (type=%d, route=%s, payload_len=%d)",
len, outbound->getPayloadType(), outbound->isRouteDirect() ? "D" : "F", outbound->payload_len);
len, outbound->getPayloadType(), outbound->isRouteDirect() ? (outbound->isRouteFuzzy() ? "Z" : "D") : "F", outbound->payload_len);
if (outbound->getPayloadType() == PAYLOAD_TYPE_PATH || outbound->getPayloadType() == PAYLOAD_TYPE_REQ
|| outbound->getPayloadType() == PAYLOAD_TYPE_RESPONSE || outbound->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
Serial.printf(" [%02X -> %02X]\n", (uint32_t)outbound->payload[1], (uint32_t)outbound->payload[0]);
Expand Down
43 changes: 28 additions & 15 deletions src/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ void Mesh::loop() {
bool Mesh::allowPacketForward(const mesh::Packet* packet) {
return false; // by default, Transport NOT enabled
}
bool Mesh::isNextHopNeighbor(const mesh::Packet* packet) {
return false; // by default, neighbor tracking not enabled
}
uint32_t Mesh::getRetransmitDelay(const mesh::Packet* packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->getRawLength()) * 52 / 50) / 2;

Expand Down Expand Up @@ -72,7 +75,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
return ACTION_RELEASE;
}

if (pkt->isRouteDirect() && pkt->getPathHashCount() > 0) {
if (pkt->isRouteDirect() && pkt->getPathHashCount() > 0 && !pkt->isPathHashOnlyFuzzy()) {
// check for 'early received' ACK
if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
int i = 0;
Expand All @@ -83,25 +86,35 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
}
}

if (self_id.isHashMatch(pkt->path, pkt->getPathHashSize()) && allowPacketForward(pkt)) {
if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) {
return forwardMultipartDirect(pkt);
} else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
if (!_tables->hasSeen(pkt)) { // don't retransmit!
removeSelfFromPath(pkt);
routeDirectRecvAcks(pkt, 0);
if (allowPacketForward(pkt)) {
bool is_next_hop = self_id.isHashMatch(pkt->path, pkt->getPathHashSize());
bool is_fuzzy_hop = !is_next_hop && pkt->isRouteFuzzy() && isNextHopNeighbor(pkt);
if (is_next_hop || is_fuzzy_hop) {
if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) {
return forwardMultipartDirect(pkt);
} else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
if (!_tables->hasSeen(pkt)) { // don't retransmit!
removeSelfFromPath(pkt);
routeDirectRecvAcks(pkt, 0);
}
return ACTION_RELEASE;
}
return ACTION_RELEASE;
}

if (!_tables->hasSeen(pkt)) {
removeSelfFromPath(pkt);
if (!_tables->hasSeen(pkt)) {
removeSelfFromPath(pkt);

uint32_t d = getDirectRetransmitDelay(pkt);

uint32_t d = getDirectRetransmitDelay(pkt);
return ACTION_RETRANSMIT_DELAYED(0, d); // Routed traffic is HIGHEST priority
if (is_next_hop) {
return ACTION_RETRANSMIT_DELAYED(0, d); // Routed traffic is HIGHEST priority
}
else {
return ACTION_RETRANSMIT_DELAYED(2, d); // Fuzzy traffic is high-ish priority
}
}
}
return ACTION_RELEASE; // this node is NOT the next hop (OR this packet has already been forwarded), so discard.
}
return ACTION_RELEASE; // this node is NOT the next hop (OR this packet has already been forwarded), so discard.
}

if (pkt->isRouteFlood() && filterRecvFloodPacket(pkt)) return ACTION_RELEASE;
Expand Down
5 changes: 5 additions & 0 deletions src/Mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ class Mesh : public Dispatcher {
*/
virtual bool allowPacketForward(const Packet* packet);

/**
* \brief Check whether this packet's next hop is a neighbor of ours.
*/
virtual bool isNextHopNeighbor(const Packet* packet);

/**
* \returns number of milliseconds delay to apply to retransmitting the given packet.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/MeshCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#define MAX_PATH_SIZE 64
#define MAX_TRANS_UNIT 255

// Denotes that everything after this prefix can be used in a "fuzzy" repeat.
// Repeated to match the path length (so 2-byte paths would use two of these, 3-byte would use 3).
#define FUZZY_PATH_PREFIX 0xFF

#if MESH_DEBUG && ARDUINO
#include <Arduino.h>
#define MESH_DEBUG_PRINT(F, ...) Serial.printf("DEBUG: " F, ##__VA_ARGS__)
Expand Down
29 changes: 29 additions & 0 deletions src/Packet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,35 @@ void Packet::calculatePacketHash(uint8_t* hash) const {
sha.finalize(hash, MAX_HASH_SIZE);
}

bool Packet::isRouteFuzzy() const {
// Only direct routes make sense for fuzzy use
if (!isRouteDirect()) {
return false;
}

// Trace is a weird situation to handle, not supported
if (getPayloadType() == PAYLOAD_TYPE_TRACE) {
return false;
}

if (!isValidPathLen(path_len)) {
return false;
}

uint8_t hash_size = getPathHashSize();
uint8_t hash_count = getPathHashCount();

uint8_t fuzzy_prefix[3]; // TODO: is there a constant somewhere for the max # of prefix bytes?
memset(fuzzy_prefix, FUZZY_PATH_PREFIX, 3);

if (memcmp(fuzzy_prefix, &path[hash_size * (hash_count - 1)], hash_size) == 0)
{
return true;
}

return false;
}

uint8_t Packet::writeTo(uint8_t dest[]) const {
uint8_t i = 0;
dest[i++] = header;
Expand Down
2 changes: 2 additions & 0 deletions src/Packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class Packet {

bool isRouteFlood() const { return getRouteType() == ROUTE_TYPE_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD; }
bool isRouteDirect() const { return getRouteType() == ROUTE_TYPE_DIRECT || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; }
bool isRouteFuzzy() const;

bool hasTransportCodes() const { return getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; }

Expand All @@ -79,6 +80,7 @@ class Packet {
uint8_t getPathHashSize() const { return (path_len >> 6) + 1; }
uint8_t getPathHashCount() const { return path_len & 63; }
uint8_t getPathByteLen() const { return getPathHashCount() * getPathHashSize(); }
bool isPathHashOnlyFuzzy() const { return getPathHashCount() == 1 && isRouteFuzzy(); }
void setPathHashCount(uint8_t n) { path_len &= ~63; path_len |= n; }
void setPathHashSizeAndCount(uint8_t sz, uint8_t n) { path_len = ((sz - 1) << 6) | (n & 63); }

Expand Down