mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge branch 'meshcore-dev:dev' into dev
This commit is contained in:
commit
7a3e01ae66
55 changed files with 653 additions and 267 deletions
|
|
@ -68,7 +68,7 @@ void Dispatcher::loop() {
|
|||
next_tx_time = futureMillis(t * getAirtimeBudgetFactor());
|
||||
|
||||
_radio->onSendFinished();
|
||||
logTx(outbound, 2 + outbound->path_len + outbound->payload_len);
|
||||
logTx(outbound, 2 + outbound->getPathByteLen() + outbound->payload_len);
|
||||
if (outbound->isRouteFlood()) {
|
||||
n_sent_flood++;
|
||||
} else {
|
||||
|
|
@ -80,7 +80,7 @@ void Dispatcher::loop() {
|
|||
MESH_DEBUG_PRINTLN("%s Dispatcher::loop(): WARNING: outbound packed send timed out!", getLogDateTime());
|
||||
|
||||
_radio->onSendFinished();
|
||||
logTxFail(outbound, 2 + outbound->path_len + outbound->payload_len);
|
||||
logTxFail(outbound, 2 + outbound->getPathByteLen() + outbound->payload_len);
|
||||
|
||||
releasePacket(outbound); // return to pool
|
||||
outbound = NULL;
|
||||
|
|
@ -108,6 +108,48 @@ void Dispatcher::loop() {
|
|||
checkSend();
|
||||
}
|
||||
|
||||
bool Dispatcher::tryParsePacket(Packet* pkt, const uint8_t* raw, int len) {
|
||||
int i = 0;
|
||||
|
||||
pkt->header = raw[i++];
|
||||
if (pkt->getPayloadVer() > PAYLOAD_VER_1) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): unsupported packet version", getLogDateTime());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkt->hasTransportCodes()) {
|
||||
memcpy(&pkt->transport_codes[0], &raw[i], 2); i += 2;
|
||||
memcpy(&pkt->transport_codes[1], &raw[i], 2); i += 2;
|
||||
} else {
|
||||
pkt->transport_codes[0] = pkt->transport_codes[1] = 0;
|
||||
}
|
||||
|
||||
pkt->path_len = raw[i++];
|
||||
uint8_t path_mode = pkt->path_len >> 6; // upper 2 bits (legacy firmware: 00)
|
||||
if (path_mode == 3) { // Reserved for future
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): unsupported path mode: 3", getLogDateTime());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t path_byte_len = (pkt->path_len & 63) * pkt->getPathHashSize();
|
||||
if (path_byte_len > MAX_PATH_SIZE || i + path_byte_len > len) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): partial or corrupt packet received, len=%d", getLogDateTime(), len);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(pkt->path, &raw[i], path_byte_len); i += path_byte_len;
|
||||
|
||||
pkt->payload_len = len - i; // payload is remainder
|
||||
if (pkt->payload_len > sizeof(pkt->payload)) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): packet payload too big, payload_len=%d", getLogDateTime(), (uint32_t)pkt->payload_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(pkt->payload, &raw[i], pkt->payload_len);
|
||||
|
||||
return true; // success
|
||||
}
|
||||
|
||||
void Dispatcher::checkRecv() {
|
||||
Packet* pkt;
|
||||
float score;
|
||||
|
|
@ -122,45 +164,14 @@ void Dispatcher::checkRecv() {
|
|||
if (pkt == NULL) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): WARNING: received data, no unused packets available!", getLogDateTime());
|
||||
} else {
|
||||
int i = 0;
|
||||
#ifdef NODE_ID
|
||||
uint8_t sender_id = raw[i++];
|
||||
if (sender_id == NODE_ID - 1 || sender_id == NODE_ID + 1) { // simulate that NODE_ID can only hear NODE_ID-1 or NODE_ID+1, eg. 3 can't hear 1
|
||||
if (tryParsePacket(pkt, raw, len)) {
|
||||
pkt->_snr = _radio->getLastSNR() * 4.0f;
|
||||
score = _radio->packetScore(_radio->getLastSNR(), len);
|
||||
air_time = _radio->getEstAirtimeFor(len);
|
||||
rx_air_time += air_time;
|
||||
} else {
|
||||
_mgr->free(pkt); // put back into pool
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
pkt->header = raw[i++];
|
||||
if (pkt->hasTransportCodes()) {
|
||||
memcpy(&pkt->transport_codes[0], &raw[i], 2); i += 2;
|
||||
memcpy(&pkt->transport_codes[1], &raw[i], 2); i += 2;
|
||||
} else {
|
||||
pkt->transport_codes[0] = pkt->transport_codes[1] = 0;
|
||||
}
|
||||
pkt->path_len = raw[i++];
|
||||
|
||||
if (pkt->path_len > MAX_PATH_SIZE || i + pkt->path_len > len) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): partial or corrupt packet received, len=%d", getLogDateTime(), len);
|
||||
_mgr->free(pkt); // put back into pool
|
||||
pkt = NULL;
|
||||
} else {
|
||||
memcpy(pkt->path, &raw[i], pkt->path_len); i += pkt->path_len;
|
||||
|
||||
pkt->payload_len = len - i; // payload is remainder
|
||||
if (pkt->payload_len > sizeof(pkt->payload)) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): packet payload too big, payload_len=%d", getLogDateTime(), (uint32_t)pkt->payload_len);
|
||||
_mgr->free(pkt); // put back into pool
|
||||
pkt = NULL;
|
||||
} else {
|
||||
memcpy(pkt->payload, &raw[i], pkt->payload_len);
|
||||
|
||||
pkt->_snr = _radio->getLastSNR() * 4.0f;
|
||||
score = _radio->packetScore(_radio->getLastSNR(), len);
|
||||
air_time = _radio->getEstAirtimeFor(len);
|
||||
rx_air_time += air_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -249,16 +260,13 @@ void Dispatcher::checkSend() {
|
|||
int len = 0;
|
||||
uint8_t raw[MAX_TRANS_UNIT];
|
||||
|
||||
#ifdef NODE_ID
|
||||
raw[len++] = NODE_ID;
|
||||
#endif
|
||||
raw[len++] = outbound->header;
|
||||
if (outbound->hasTransportCodes()) {
|
||||
memcpy(&raw[len], &outbound->transport_codes[0], 2); len += 2;
|
||||
memcpy(&raw[len], &outbound->transport_codes[1], 2); len += 2;
|
||||
}
|
||||
raw[len++] = outbound->path_len;
|
||||
memcpy(&raw[len], outbound->path, outbound->path_len); len += outbound->path_len;
|
||||
len += Packet::writePath(&raw[len], outbound->path, outbound->path_len);
|
||||
|
||||
if (len + outbound->payload_len > MAX_TRANS_UNIT) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkSend(): FATAL: Invalid packet queued... too long, len=%d", getLogDateTime(), len + outbound->payload_len);
|
||||
|
|
@ -312,7 +320,7 @@ void Dispatcher::releasePacket(Packet* packet) {
|
|||
}
|
||||
|
||||
void Dispatcher::sendPacket(Packet* packet, uint8_t priority, uint32_t delay_millis) {
|
||||
if (packet->path_len > MAX_PATH_SIZE || packet->payload_len > MAX_PACKET_PAYLOAD) {
|
||||
if (!Packet::isValidPathLen(packet->path_len) || packet->payload_len > MAX_PACKET_PAYLOAD) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::sendPacket(): ERROR: invalid packet... path_len=%d, payload_len=%d", getLogDateTime(), (uint32_t) packet->path_len, (uint32_t) packet->payload_len);
|
||||
_mgr->free(packet);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ public:
|
|||
unsigned long futureMillis(int millis_from_now) const;
|
||||
|
||||
private:
|
||||
bool tryParsePacket(Packet* pkt, const uint8_t* raw, int len);
|
||||
void checkRecv();
|
||||
void checkSend();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ public:
|
|||
memcpy(dest, pub_key, PATH_HASH_SIZE); // hash is just prefix of pub_key
|
||||
return PATH_HASH_SIZE;
|
||||
}
|
||||
int copyHashTo(uint8_t* dest, uint8_t len) const {
|
||||
memcpy(dest, pub_key, len); // hash is just prefix of pub_key
|
||||
return len;
|
||||
}
|
||||
bool isHashMatch(const uint8_t* hash) const {
|
||||
return memcmp(hash, pub_key, PATH_HASH_SIZE) == 0;
|
||||
}
|
||||
|
|
|
|||
74
src/Mesh.cpp
74
src/Mesh.cpp
|
|
@ -39,11 +39,6 @@ int Mesh::searchChannelsByHash(const uint8_t* hash, GroupChannel channels[], int
|
|||
}
|
||||
|
||||
DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
if (pkt->getPayloadVer() > PAYLOAD_VER_1) { // not supported in this firmware version
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): unsupported packet version", getLogDateTime());
|
||||
return ACTION_RELEASE;
|
||||
}
|
||||
|
||||
if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) {
|
||||
if (pkt->path_len < MAX_PATH_SIZE) {
|
||||
uint8_t i = 0;
|
||||
|
|
@ -70,14 +65,14 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||
}
|
||||
|
||||
if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_CONTROL && (pkt->payload[0] & 0x80) != 0) {
|
||||
if (pkt->path_len == 0) {
|
||||
if (pkt->getPathHashCount() == 0) {
|
||||
onControlDataRecv(pkt);
|
||||
}
|
||||
// just zero-hop control packets allowed (for this subset of payloads)
|
||||
return ACTION_RELEASE;
|
||||
}
|
||||
|
||||
if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) {
|
||||
if (pkt->isRouteDirect() && pkt->getPathHashCount() > 0) {
|
||||
// check for 'early received' ACK
|
||||
if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
|
||||
int i = 0;
|
||||
|
|
@ -88,7 +83,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||
}
|
||||
}
|
||||
|
||||
if (self_id.isHashMatch(pkt->path) && allowPacketForward(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) {
|
||||
|
|
@ -158,7 +153,9 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
||||
int k = 0;
|
||||
uint8_t path_len = data[k++];
|
||||
uint8_t* path = &data[k]; k += path_len;
|
||||
uint8_t hash_size = (path_len >> 6) + 1;
|
||||
uint8_t hash_count = path_len & 63;
|
||||
uint8_t* path = &data[k]; k += hash_size*hash_count;
|
||||
uint8_t extra_type = data[k++] & 0x0F; // upper 4 bits reserved for future use
|
||||
uint8_t* extra = &data[k];
|
||||
uint8_t extra_len = len - k; // remainder of packet (may be padded with zeroes!)
|
||||
|
|
@ -293,8 +290,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||
if (type == PAYLOAD_TYPE_ACK && pkt->payload_len >= 5) { // a multipart ACK
|
||||
Packet tmp;
|
||||
tmp.header = pkt->header;
|
||||
tmp.path_len = pkt->path_len;
|
||||
memcpy(tmp.path, pkt->path, pkt->path_len);
|
||||
tmp.path_len = Packet::copyPath(tmp.path, pkt->path, pkt->path_len);
|
||||
tmp.payload_len = pkt->payload_len - 1;
|
||||
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
||||
|
||||
|
|
@ -321,27 +317,25 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||
|
||||
void Mesh::removeSelfFromPath(Packet* pkt) {
|
||||
// remove our hash from 'path'
|
||||
pkt->path_len -= PATH_HASH_SIZE;
|
||||
#if 0
|
||||
memcpy(pkt->path, &pkt->path[PATH_HASH_SIZE], pkt->path_len);
|
||||
#elif PATH_HASH_SIZE == 1
|
||||
for (int k = 0; k < pkt->path_len; k++) { // shuffle bytes by 1
|
||||
pkt->path[k] = pkt->path[k + 1];
|
||||
pkt->setPathHashCount(pkt->getPathHashCount() - 1); // decrement the count
|
||||
|
||||
uint8_t sz = pkt->getPathHashSize();
|
||||
for (int k = 0; k < pkt->getPathHashCount()*sz; k += sz) { // shuffle path by 1 'entry'
|
||||
memcpy(&pkt->path[k], &pkt->path[k + sz], sz);
|
||||
}
|
||||
#else
|
||||
#error "need path remove impl"
|
||||
#endif
|
||||
}
|
||||
|
||||
DispatcherAction Mesh::routeRecvPacket(Packet* packet) {
|
||||
uint8_t n = packet->getPathHashCount();
|
||||
if (packet->isRouteFlood() && !packet->isMarkedDoNotRetransmit()
|
||||
&& packet->path_len + PATH_HASH_SIZE <= MAX_PATH_SIZE && allowPacketForward(packet)) {
|
||||
&& (n + 1)*packet->getPathHashSize() <= MAX_PATH_SIZE && allowPacketForward(packet)) {
|
||||
// append this node's hash to 'path'
|
||||
packet->path_len += self_id.copyHashTo(&packet->path[packet->path_len]);
|
||||
self_id.copyHashTo(&packet->path[n * packet->getPathHashSize()], packet->getPathHashSize());
|
||||
packet->setPathHashCount(n + 1);
|
||||
|
||||
uint32_t d = getRetransmitDelay(packet);
|
||||
// as this propagates outwards, give it lower and lower priority
|
||||
return ACTION_RETRANSMIT_DELAYED(packet->path_len, d); // give priority to closer sources, than ones further away
|
||||
return ACTION_RETRANSMIT_DELAYED(packet->getPathHashCount(), d); // give priority to closer sources, than ones further away
|
||||
}
|
||||
return ACTION_RELEASE;
|
||||
}
|
||||
|
|
@ -353,8 +347,7 @@ DispatcherAction Mesh::forwardMultipartDirect(Packet* pkt) {
|
|||
if (type == PAYLOAD_TYPE_ACK && pkt->payload_len >= 5) { // a multipart ACK
|
||||
Packet tmp;
|
||||
tmp.header = pkt->header;
|
||||
tmp.path_len = pkt->path_len;
|
||||
memcpy(tmp.path, pkt->path, pkt->path_len);
|
||||
tmp.path_len = Packet::copyPath(tmp.path, pkt->path, pkt->path_len);
|
||||
tmp.payload_len = pkt->payload_len - 1;
|
||||
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
||||
|
||||
|
|
@ -376,7 +369,7 @@ void Mesh::routeDirectRecvAcks(Packet* packet, uint32_t delay_millis) {
|
|||
delay_millis += getDirectRetransmitDelay(packet) + 300;
|
||||
auto a1 = createMultiAck(crc, extra);
|
||||
if (a1) {
|
||||
memcpy(a1->path, packet->path, a1->path_len = packet->path_len);
|
||||
a1->path_len = Packet::copyPath(a1->path, packet->path, packet->path_len);
|
||||
a1->header &= ~PH_ROUTE_MASK;
|
||||
a1->header |= ROUTE_TYPE_DIRECT;
|
||||
sendPacket(a1, 0, delay_millis);
|
||||
|
|
@ -386,7 +379,7 @@ void Mesh::routeDirectRecvAcks(Packet* packet, uint32_t delay_millis) {
|
|||
|
||||
auto a2 = createAck(crc);
|
||||
if (a2) {
|
||||
memcpy(a2->path, packet->path, a2->path_len = packet->path_len);
|
||||
a2->path_len = Packet::copyPath(a2->path, packet->path, packet->path_len);
|
||||
a2->header &= ~PH_ROUTE_MASK;
|
||||
a2->header |= ROUTE_TYPE_DIRECT;
|
||||
sendPacket(a2, 0, delay_millis);
|
||||
|
|
@ -439,7 +432,10 @@ Packet* Mesh::createPathReturn(const Identity& dest, const uint8_t* secret, cons
|
|||
}
|
||||
|
||||
Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len) {
|
||||
if (path_len + extra_len + 5 > MAX_COMBINED_PATH) return NULL; // too long!!
|
||||
uint8_t path_hash_size = (path_len >> 6) + 1;
|
||||
uint8_t path_hash_count = path_len & 63;
|
||||
|
||||
if (path_hash_count*path_hash_size + extra_len + 5 > MAX_COMBINED_PATH) return NULL; // too long!!
|
||||
|
||||
Packet* packet = obtainNewPacket();
|
||||
if (packet == NULL) {
|
||||
|
|
@ -457,7 +453,7 @@ Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret,
|
|||
uint8_t data[MAX_PACKET_PAYLOAD];
|
||||
|
||||
data[data_len++] = path_len;
|
||||
memcpy(&data[data_len], path, path_len); data_len += path_len;
|
||||
memcpy(&data[data_len], path, path_hash_count*path_hash_size); data_len += path_hash_count*path_hash_size;
|
||||
if (extra_len > 0) {
|
||||
data[data_len++] = extra_type;
|
||||
memcpy(&data[data_len], extra, extra_len); data_len += extra_len;
|
||||
|
|
@ -624,15 +620,19 @@ Packet* Mesh::createControlData(const uint8_t* data, size_t len) {
|
|||
return packet;
|
||||
}
|
||||
|
||||
void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) {
|
||||
void Mesh::sendFlood(Packet* packet, uint32_t delay_millis, uint8_t path_hash_size) {
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime());
|
||||
return;
|
||||
}
|
||||
if (path_hash_size == 0 || path_hash_size > 3) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): invalid path_hash_size", getLogDateTime());
|
||||
return;
|
||||
}
|
||||
|
||||
packet->header &= ~PH_ROUTE_MASK;
|
||||
packet->header |= ROUTE_TYPE_FLOOD;
|
||||
packet->path_len = 0;
|
||||
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
||||
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
|
||||
|
|
@ -647,17 +647,21 @@ void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) {
|
|||
sendPacket(packet, pri, delay_millis);
|
||||
}
|
||||
|
||||
void Mesh::sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis) {
|
||||
void Mesh::sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis, uint8_t path_hash_size) {
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime());
|
||||
return;
|
||||
}
|
||||
if (path_hash_size == 0 || path_hash_size > 3) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): invalid path_hash_size", getLogDateTime());
|
||||
return;
|
||||
}
|
||||
|
||||
packet->header &= ~PH_ROUTE_MASK;
|
||||
packet->header |= ROUTE_TYPE_TRANSPORT_FLOOD;
|
||||
packet->transport_codes[0] = transport_codes[0];
|
||||
packet->transport_codes[1] = transport_codes[1];
|
||||
packet->path_len = 0;
|
||||
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
||||
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
|
||||
|
|
@ -679,13 +683,13 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin
|
|||
uint8_t pri;
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { // TRACE packets are different
|
||||
// for TRACE packets, path is appended to end of PAYLOAD. (path is used for SNR's)
|
||||
memcpy(&packet->payload[packet->payload_len], path, path_len);
|
||||
memcpy(&packet->payload[packet->payload_len], path, path_len); // NOTE: path_len here can be > 64, and NOT in the new scheme
|
||||
packet->payload_len += path_len;
|
||||
|
||||
packet->path_len = 0;
|
||||
pri = 5; // maybe make this configurable
|
||||
} else {
|
||||
memcpy(packet->path, path, packet->path_len = path_len);
|
||||
packet->path_len = Packet::copyPath(packet->path, path, path_len);
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
||||
pri = 1; // slightly less priority
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -196,13 +196,13 @@ public:
|
|||
/**
|
||||
* \brief send a locally-generated Packet with flood routing
|
||||
*/
|
||||
void sendFlood(Packet* packet, uint32_t delay_millis=0);
|
||||
void sendFlood(Packet* packet, uint32_t delay_millis=0, uint8_t path_hash_size=1);
|
||||
|
||||
/**
|
||||
* \brief send a locally-generated Packet with flood routing
|
||||
* \param transport_codes array of 2 codes to attach to packet
|
||||
*/
|
||||
void sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis=0);
|
||||
void sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis=0, uint8_t path_hash_size=1);
|
||||
|
||||
/**
|
||||
* \brief send a locally-generated Packet with Direct routing
|
||||
|
|
|
|||
|
|
@ -10,8 +10,32 @@ Packet::Packet() {
|
|||
payload_len = 0;
|
||||
}
|
||||
|
||||
bool Packet::isValidPathLen(uint8_t path_len) {
|
||||
uint8_t hash_count = path_len & 63;
|
||||
uint8_t hash_size = (path_len >> 6) + 1;
|
||||
if (hash_size == 4) return false; // Reserved for future
|
||||
return hash_count*hash_size <= MAX_PATH_SIZE;
|
||||
}
|
||||
|
||||
size_t Packet::writePath(uint8_t* dest, const uint8_t* src, uint8_t path_len) {
|
||||
uint8_t hash_count = path_len & 63;
|
||||
uint8_t hash_size = (path_len >> 6) + 1;
|
||||
size_t len = hash_count*hash_size;
|
||||
if (len > MAX_PATH_SIZE) {
|
||||
MESH_DEBUG_PRINTLN("Packet::copyPath, invalid path_len=%d", (uint32_t)path_len);
|
||||
return 0; // Error
|
||||
}
|
||||
memcpy(dest, src, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t Packet::copyPath(uint8_t* dest, const uint8_t* src, uint8_t path_len) {
|
||||
writePath(dest, src, path_len);
|
||||
return path_len;
|
||||
}
|
||||
|
||||
int Packet::getRawLength() const {
|
||||
return 2 + path_len + payload_len + (hasTransportCodes() ? 4 : 0);
|
||||
return 2 + getPathByteLen() + payload_len + (hasTransportCodes() ? 4 : 0);
|
||||
}
|
||||
|
||||
void Packet::calculatePacketHash(uint8_t* hash) const {
|
||||
|
|
@ -33,7 +57,7 @@ uint8_t Packet::writeTo(uint8_t dest[]) const {
|
|||
memcpy(&dest[i], &transport_codes[1], 2); i += 2;
|
||||
}
|
||||
dest[i++] = path_len;
|
||||
memcpy(&dest[i], path, path_len); i += path_len;
|
||||
i += writePath(&dest[i], path, path_len);
|
||||
memcpy(&dest[i], payload, payload_len); i += payload_len;
|
||||
return i;
|
||||
}
|
||||
|
|
@ -48,8 +72,11 @@ bool Packet::readFrom(const uint8_t src[], uint8_t len) {
|
|||
transport_codes[0] = transport_codes[1] = 0;
|
||||
}
|
||||
path_len = src[i++];
|
||||
if (path_len > sizeof(path)) return false; // bad encoding
|
||||
memcpy(path, &src[i], path_len); i += path_len;
|
||||
if (!isValidPathLen(path_len)) return false; // bad encoding
|
||||
|
||||
uint8_t bl = getPathByteLen();
|
||||
memcpy(path, &src[i], bl); i += bl;
|
||||
|
||||
if (i >= len) return false; // bad encoding
|
||||
payload_len = len - i;
|
||||
if (payload_len > sizeof(payload)) return false; // bad encoding
|
||||
|
|
|
|||
10
src/Packet.h
10
src/Packet.h
|
|
@ -76,6 +76,16 @@ public:
|
|||
*/
|
||||
uint8_t getPayloadVer() const { return (header >> PH_VER_SHIFT) & PH_VER_MASK; }
|
||||
|
||||
uint8_t getPathHashSize() const { return (path_len >> 6) + 1; }
|
||||
uint8_t getPathHashCount() const { return path_len & 63; }
|
||||
uint8_t getPathByteLen() const { return getPathHashCount() * getPathHashSize(); }
|
||||
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); }
|
||||
|
||||
static uint8_t copyPath(uint8_t* dest, const uint8_t* src, uint8_t path_len); // returns path_len
|
||||
static size_t writePath(uint8_t* dest, const uint8_t* src, uint8_t path_len); // returns byte length written
|
||||
static bool isValidPathLen(uint8_t path_len);
|
||||
|
||||
void markDoNotRetransmit() { header = 0xFF; }
|
||||
bool isMarkedDoNotRetransmit() const { return header == 0xFF; }
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name, double lat, doubl
|
|||
}
|
||||
|
||||
void BaseChatMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) {
|
||||
if (dest.out_path_len < 0) {
|
||||
if (dest.out_path_len == OUT_PATH_UNKNOWN) {
|
||||
mesh::Packet* ack = createAck(ack_hash);
|
||||
if (ack) sendFloodScoped(dest, ack, TXT_ACK_DELAY);
|
||||
} else {
|
||||
|
|
@ -92,7 +92,7 @@ ContactInfo* BaseChatMesh::allocateContactSlot() {
|
|||
void BaseChatMesh::populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp) {
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
ci.id = id;
|
||||
ci.out_path_len = -1; // initially out_path is unknown
|
||||
ci.out_path_len = OUT_PATH_UNKNOWN;
|
||||
StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name));
|
||||
ci.type = parser.getType();
|
||||
if (parser.hasLatLon()) {
|
||||
|
|
@ -141,6 +141,15 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id,
|
|||
return;
|
||||
}
|
||||
|
||||
// check hop limit for new contacts (0 = no limit, 1 = direct (0 hops), N = up to N-1 hops)
|
||||
uint8_t max_hops = getAutoAddMaxHops();
|
||||
if (max_hops > 0 && packet->getPathHashCount() >= max_hops) {
|
||||
ContactInfo ci;
|
||||
populateContactFromAdvert(ci, id, parser, timestamp);
|
||||
onDiscoveredContact(ci, true, packet->path_len, packet->path); // let UI know
|
||||
return;
|
||||
}
|
||||
|
||||
from = allocateContactSlot();
|
||||
if (from == NULL) {
|
||||
ContactInfo ci;
|
||||
|
|
@ -263,7 +272,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
|
|||
} else {
|
||||
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, from.id, secret, temp_buf, reply_len);
|
||||
if (reply) {
|
||||
if (from.out_path_len >= 0) { // we have an out_path, so send DIRECT
|
||||
if (from.out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
|
||||
sendDirect(reply, from.out_path, from.out_path_len, SERVER_RESPONSE_DELAY);
|
||||
} else {
|
||||
sendFloodScoped(from, reply, SERVER_RESPONSE_DELAY);
|
||||
|
|
@ -273,7 +282,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
|
|||
}
|
||||
} else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) {
|
||||
onContactResponse(from, data, len);
|
||||
if (packet->isRouteFlood() && from.out_path_len >= 0) {
|
||||
if (packet->isRouteFlood() && from.out_path_len != OUT_PATH_UNKNOWN) {
|
||||
// we have direct path, but other node is still sending flood response, so maybe they didn't receive reciprocal path properly(?)
|
||||
handleReturnPathRetry(from, packet->path, packet->path_len);
|
||||
}
|
||||
|
|
@ -295,7 +304,7 @@ bool BaseChatMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const ui
|
|||
bool BaseChatMesh::onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) {
|
||||
// NOTE: default impl, we just replace the current 'out_path' regardless, whenever sender sends us a new out_path.
|
||||
// FUTURE: could store multiple out_paths per contact, and try to find which is the 'best'(?)
|
||||
memcpy(from.out_path, out_path, from.out_path_len = out_path_len); // store a copy of path, for sendDirect()
|
||||
from.out_path_len = mesh::Packet::copyPath(from.out_path, out_path, out_path_len); // store a copy of path, for sendDirect()
|
||||
from.lastmod = getRTCClock()->getCurrentTime();
|
||||
|
||||
onContactPathUpdated(from);
|
||||
|
|
@ -317,7 +326,7 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
|
|||
txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer
|
||||
packet->markDoNotRetransmit(); // ACK was for this node, so don't retransmit
|
||||
|
||||
if (packet->isRouteFlood() && from->out_path_len >= 0) {
|
||||
if (packet->isRouteFlood() && from->out_path_len != OUT_PATH_UNKNOWN) {
|
||||
// we have direct path, but other node is still sending flood, so maybe they didn't receive reciprocal path properly(?)
|
||||
handleReturnPathRetry(*from, packet->path, packet->path_len);
|
||||
}
|
||||
|
|
@ -386,7 +395,7 @@ int BaseChatMesh::sendMessage(const ContactInfo& recipient, uint32_t timestamp,
|
|||
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
|
||||
|
||||
int rc;
|
||||
if (recipient.out_path_len < 0) {
|
||||
if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
|
||||
sendFloodScoped(recipient, pkt);
|
||||
txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t));
|
||||
rc = MSG_SEND_SENT_FLOOD;
|
||||
|
|
@ -412,7 +421,7 @@ int BaseChatMesh::sendCommandData(const ContactInfo& recipient, uint32_t timest
|
|||
|
||||
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
|
||||
int rc;
|
||||
if (recipient.out_path_len < 0) {
|
||||
if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
|
||||
sendFloodScoped(recipient, pkt);
|
||||
txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t));
|
||||
rc = MSG_SEND_SENT_FLOOD;
|
||||
|
|
@ -500,7 +509,7 @@ int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password,
|
|||
}
|
||||
if (pkt) {
|
||||
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
|
||||
if (recipient.out_path_len < 0) {
|
||||
if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
|
||||
sendFloodScoped(recipient, pkt);
|
||||
est_timeout = calcFloodTimeoutMillisFor(t);
|
||||
return MSG_SEND_SENT_FLOOD;
|
||||
|
|
@ -525,7 +534,7 @@ int BaseChatMesh::sendAnonReq(const ContactInfo& recipient, const uint8_t* data,
|
|||
}
|
||||
if (pkt) {
|
||||
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
|
||||
if (recipient.out_path_len < 0) {
|
||||
if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
|
||||
sendFloodScoped(recipient, pkt);
|
||||
est_timeout = calcFloodTimeoutMillisFor(t);
|
||||
return MSG_SEND_SENT_FLOOD;
|
||||
|
|
@ -552,7 +561,7 @@ int BaseChatMesh::sendRequest(const ContactInfo& recipient, const uint8_t* req_
|
|||
}
|
||||
if (pkt) {
|
||||
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
|
||||
if (recipient.out_path_len < 0) {
|
||||
if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
|
||||
sendFloodScoped(recipient, pkt);
|
||||
est_timeout = calcFloodTimeoutMillisFor(t);
|
||||
return MSG_SEND_SENT_FLOOD;
|
||||
|
|
@ -579,7 +588,7 @@ int BaseChatMesh::sendRequest(const ContactInfo& recipient, uint8_t req_type, u
|
|||
}
|
||||
if (pkt) {
|
||||
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
|
||||
if (recipient.out_path_len < 0) {
|
||||
if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
|
||||
sendFloodScoped(recipient, pkt);
|
||||
est_timeout = calcFloodTimeoutMillisFor(t);
|
||||
return MSG_SEND_SENT_FLOOD;
|
||||
|
|
@ -683,7 +692,7 @@ void BaseChatMesh::checkConnections() {
|
|||
MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact not found!");
|
||||
continue;
|
||||
}
|
||||
if (contact->out_path_len < 0) {
|
||||
if (contact->out_path_len == OUT_PATH_UNKNOWN) {
|
||||
MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact, no out_path!");
|
||||
continue;
|
||||
}
|
||||
|
|
@ -710,7 +719,7 @@ void BaseChatMesh::checkConnections() {
|
|||
}
|
||||
|
||||
void BaseChatMesh::resetPathTo(ContactInfo& recipient) {
|
||||
recipient.out_path_len = -1;
|
||||
recipient.out_path_len = OUT_PATH_UNKNOWN;
|
||||
}
|
||||
|
||||
static ContactInfo* table; // pass via global :-(
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ protected:
|
|||
virtual bool shouldAutoAddContactType(uint8_t type) const { return true; }
|
||||
virtual void onContactsFull() {};
|
||||
virtual bool shouldOverwriteWhenFull() const { return false; }
|
||||
virtual uint8_t getAutoAddMaxHops() const { return 0; } // 0 = no limit, 1 = direct (0 hops), N = up to N-1 hops
|
||||
virtual void onContactOverwrite(const uint8_t* pub_key) {};
|
||||
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0;
|
||||
virtual ContactInfo* processAck(const uint8_t *data) = 0;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ ClientInfo* ClientACL::putClient(const mesh::Identity& id, uint8_t init_perms) {
|
|||
memset(c, 0, sizeof(*c));
|
||||
c->permissions = init_perms;
|
||||
c->id = id;
|
||||
c->out_path_len = -1; // initially out_path is unknown
|
||||
c->out_path_len = OUT_PATH_UNKNOWN;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,12 @@
|
|||
#define PERM_ACL_READ_WRITE 2
|
||||
#define PERM_ACL_ADMIN 3
|
||||
|
||||
#define OUT_PATH_UNKNOWN 0xFF
|
||||
|
||||
struct ClientInfo {
|
||||
mesh::Identity id;
|
||||
uint8_t permissions;
|
||||
int8_t out_path_len;
|
||||
uint8_t out_path_len;
|
||||
uint8_t out_path[MAX_PATH_SIZE];
|
||||
uint8_t shared_secret[PUB_KEY_SIZE];
|
||||
uint32_t last_timestamp; // by THEIR clock (transient)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
|||
file.read((uint8_t *)&_prefs->multi_acks, sizeof(_prefs->multi_acks)); // 115
|
||||
file.read((uint8_t *)&_prefs->bw, sizeof(_prefs->bw)); // 116
|
||||
file.read((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
|
||||
file.read(pad, 3); // 121
|
||||
file.read((uint8_t *)&_prefs->path_hash_mode, sizeof(_prefs->path_hash_mode)); // 121
|
||||
file.read((uint8_t *)&_prefs->loop_detect, sizeof(_prefs->loop_detect)); // 122
|
||||
file.read(pad, 1); // 123
|
||||
file.read((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
|
||||
file.read((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
|
||||
file.read((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
|
||||
|
|
@ -95,6 +97,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
|||
_prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, -9, 30);
|
||||
_prefs->multi_acks = constrain(_prefs->multi_acks, 0, 1);
|
||||
_prefs->adc_multiplier = constrain(_prefs->adc_multiplier, 0.0f, 10.0f);
|
||||
_prefs->path_hash_mode = constrain(_prefs->path_hash_mode, 0, 2); // NOTE: mode 3 reserved for future
|
||||
|
||||
// sanitise bad bridge pref values
|
||||
_prefs->bridge_enabled = constrain(_prefs->bridge_enabled, 0, 1);
|
||||
|
|
@ -147,7 +150,9 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
|||
file.write((uint8_t *)&_prefs->multi_acks, sizeof(_prefs->multi_acks)); // 115
|
||||
file.write((uint8_t *)&_prefs->bw, sizeof(_prefs->bw)); // 116
|
||||
file.write((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
|
||||
file.write(pad, 3); // 121
|
||||
file.write((uint8_t *)&_prefs->path_hash_mode, sizeof(_prefs->path_hash_mode)); // 121
|
||||
file.write((uint8_t *)&_prefs->loop_detect, sizeof(_prefs->loop_detect)); // 122
|
||||
file.write(pad, 1); // 123
|
||||
file.write((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
|
||||
file.write((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
|
||||
file.write((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
|
||||
|
|
@ -200,6 +205,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||
// Reset clock
|
||||
getRTCClock()->setCurrentTime(1715770351); // 15 May 2024, 8:50pm
|
||||
_board->reboot(); // doesn't return
|
||||
} else if (memcmp(command, "advert.zerohop", 14) == 0 && (command[14] == 0 || command[14] == ' ')) {
|
||||
// send zerohop advert
|
||||
_callbacks->sendSelfAdvertisement(1500, false); // longer delay, give CLI response time to be sent first
|
||||
strcpy(reply, "OK - zerohop advert sent");
|
||||
} else if (memcmp(command, "advert", 6) == 0) {
|
||||
// send flood advert
|
||||
_callbacks->sendSelfAdvertisement(1500, true); // longer delay, give CLI response time to be sent first
|
||||
|
|
@ -325,6 +334,18 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||
sp++;
|
||||
}
|
||||
*reply = 0; // set null terminator
|
||||
} else if (memcmp(config, "path.hash.mode", 14) == 0) {
|
||||
sprintf(reply, "> %d", (uint32_t)_prefs->path_hash_mode);
|
||||
} else if (memcmp(config, "loop.detect", 11) == 0) {
|
||||
if (_prefs->loop_detect == LOOP_DETECT_OFF) {
|
||||
strcpy(reply, "> off");
|
||||
} else if (_prefs->loop_detect == LOOP_DETECT_MINIMAL) {
|
||||
strcpy(reply, "> minimal");
|
||||
} else if (_prefs->loop_detect == LOOP_DETECT_MODERATE) {
|
||||
strcpy(reply, "> moderate");
|
||||
} else {
|
||||
strcpy(reply, "> strict");
|
||||
}
|
||||
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) {
|
||||
sprintf(reply, "> %d", (int32_t) _prefs->tx_power_dbm);
|
||||
} else if (memcmp(config, "freq", 4) == 0) {
|
||||
|
|
@ -556,6 +577,36 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||
*dp = 0;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "path.hash.mode ", 15) == 0) {
|
||||
config += 15;
|
||||
uint8_t mode = atoi(config);
|
||||
if (mode < 3) {
|
||||
_prefs->path_hash_mode = mode;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else {
|
||||
strcpy(reply, "Error, must be 0,1, or 2");
|
||||
}
|
||||
} else if (memcmp(config, "loop.detect ", 12) == 0) {
|
||||
config += 12;
|
||||
uint8_t mode;
|
||||
if (memcmp(config, "off", 3) == 0) {
|
||||
mode = LOOP_DETECT_OFF;
|
||||
} else if (memcmp(config, "minimal", 7) == 0) {
|
||||
mode = LOOP_DETECT_MINIMAL;
|
||||
} else if (memcmp(config, "moderate", 8) == 0) {
|
||||
mode = LOOP_DETECT_MODERATE;
|
||||
} else if (memcmp(config, "strict", 6) == 0) {
|
||||
mode = LOOP_DETECT_STRICT;
|
||||
} else {
|
||||
mode = 0xFF;
|
||||
strcpy(reply, "Error, must be: off, minimal, moderate, or strict");
|
||||
}
|
||||
if (mode != 0xFF) {
|
||||
_prefs->loop_detect = mode;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
}
|
||||
} else if (memcmp(config, "tx ", 3) == 0) {
|
||||
_prefs->tx_power_dbm = atoi(&config[3]);
|
||||
savePrefs();
|
||||
|
|
@ -702,6 +753,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||
LocationProvider * l = _sensors->getLocationProvider();
|
||||
if (l != NULL) {
|
||||
l->syncTime();
|
||||
strcpy(reply, "ok");
|
||||
} else {
|
||||
strcpy(reply, "gps provider not found");
|
||||
}
|
||||
} else if (memcmp(command, "gps setloc", 10) == 0) {
|
||||
_prefs->node_lat = _sensors->node_lat;
|
||||
|
|
@ -731,7 +785,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||
_prefs->advert_loc_policy = ADVERT_LOC_SHARE;
|
||||
savePrefs();
|
||||
strcpy(reply, "ok");
|
||||
} else if (memcmp(command+11, "prefs", 4) == 0) {
|
||||
} else if (memcmp(command+11, "prefs", 5) == 0) {
|
||||
_prefs->advert_loc_policy = ADVERT_LOC_PREFS;
|
||||
savePrefs();
|
||||
strcpy(reply, "ok");
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
#define ADVERT_LOC_SHARE 1
|
||||
#define ADVERT_LOC_PREFS 2
|
||||
|
||||
#define LOOP_DETECT_OFF 0
|
||||
#define LOOP_DETECT_MINIMAL 1
|
||||
#define LOOP_DETECT_MODERATE 2
|
||||
#define LOOP_DETECT_STRICT 3
|
||||
|
||||
struct NodePrefs { // persisted to file
|
||||
float airtime_factor;
|
||||
char node_name[32];
|
||||
|
|
@ -52,6 +57,8 @@ struct NodePrefs { // persisted to file
|
|||
uint32_t discovery_mod_timestamp;
|
||||
float adc_multiplier;
|
||||
char owner_info[120];
|
||||
uint8_t path_hash_mode; // which path mode to use when sending
|
||||
uint8_t loop_detect;
|
||||
};
|
||||
|
||||
class CommonCLICallbacks {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@
|
|||
#include <Arduino.h>
|
||||
#include <Mesh.h>
|
||||
|
||||
#define OUT_PATH_UNKNOWN 0xFF
|
||||
|
||||
struct ContactInfo {
|
||||
mesh::Identity id;
|
||||
char name[32];
|
||||
uint8_t type; // on of ADV_TYPE_*
|
||||
uint8_t flags;
|
||||
int8_t out_path_len;
|
||||
uint8_t out_path_len;
|
||||
mutable bool shared_secret_valid; // flag to indicate if shared_secret has been calculated
|
||||
uint8_t out_path[MAX_PATH_SIZE];
|
||||
uint32_t last_advert_timestamp; // by THEIR clock
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ public:
|
|||
digitalWrite(_pin, _active);
|
||||
}
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (_claims == 0) return; // avoid negative _claims
|
||||
|
||||
_claims--;
|
||||
if (_claims == 0) {
|
||||
digitalWrite(_pin, !_active);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "CustomLLCC68.h"
|
||||
#include "RadioLibWrappers.h"
|
||||
#include "SX126xReset.h"
|
||||
|
||||
class CustomLLCC68Wrapper : public RadioLibWrapper {
|
||||
public:
|
||||
|
|
@ -19,4 +20,6 @@ public:
|
|||
int sf = ((CustomLLCC68 *)_radio)->spreadingFactor;
|
||||
return packetScoreInt(snr, sf, packet_len);
|
||||
}
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class CustomLR1110 : public LR1110 {
|
|||
return len;
|
||||
}
|
||||
|
||||
float getFreqMHz() const { return freqMHz; }
|
||||
|
||||
bool isReceiving() {
|
||||
uint16_t irq = getIrqStatus();
|
||||
bool detected = ((irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID) || (irq & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED));
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
#include "CustomLR1110.h"
|
||||
#include "RadioLibWrappers.h"
|
||||
#include "LR11x0Reset.h"
|
||||
|
||||
class CustomLR1110Wrapper : public RadioLibWrapper {
|
||||
public:
|
||||
CustomLR1110Wrapper(CustomLR1110& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { }
|
||||
bool isReceivingPacket() override {
|
||||
void doResetAGC() override { lr11x0ResetAGC((LR11x0 *)_radio, ((CustomLR1110 *)_radio)->getFreqMHz()); }
|
||||
bool isReceivingPacket() override {
|
||||
return ((CustomLR1110 *)_radio)->isReceiving();
|
||||
}
|
||||
float getCurrentRSSI() override {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "CustomSTM32WLx.h"
|
||||
#include "RadioLibWrappers.h"
|
||||
#include "SX126xReset.h"
|
||||
#include <math.h>
|
||||
|
||||
class CustomSTM32WLxWrapper : public RadioLibWrapper {
|
||||
|
|
@ -20,4 +21,6 @@ public:
|
|||
int sf = ((CustomSTM32WLx *)_radio)->spreadingFactor;
|
||||
return packetScoreInt(snr, sf, packet_len);
|
||||
}
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "CustomSX1262.h"
|
||||
#include "RadioLibWrappers.h"
|
||||
#include "SX126xReset.h"
|
||||
|
||||
class CustomSX1262Wrapper : public RadioLibWrapper {
|
||||
public:
|
||||
|
|
@ -22,4 +23,6 @@ public:
|
|||
virtual void powerOff() override {
|
||||
((CustomSX1262 *)_radio)->sleep(false);
|
||||
}
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "CustomSX1268.h"
|
||||
#include "RadioLibWrappers.h"
|
||||
#include "SX126xReset.h"
|
||||
|
||||
class CustomSX1268Wrapper : public RadioLibWrapper {
|
||||
public:
|
||||
|
|
@ -19,4 +20,6 @@ public:
|
|||
int sf = ((CustomSX1268 *)_radio)->spreadingFactor;
|
||||
return packetScoreInt(snr, sf, packet_len);
|
||||
}
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
};
|
||||
|
|
|
|||
21
src/helpers/radiolib/LR11x0Reset.h
Normal file
21
src/helpers/radiolib/LR11x0Reset.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <RadioLib.h>
|
||||
|
||||
// Full receiver reset for LR11x0-family chips (LR1110, LR1120, LR1121).
|
||||
// Warm sleep powers down analog, calibrate(0x3F) refreshes all calibration blocks,
|
||||
// then re-applies RX settings that calibration may reset.
|
||||
inline void lr11x0ResetAGC(LR11x0* radio, float freqMHz) {
|
||||
radio->sleep(true, 0);
|
||||
radio->standby(RADIOLIB_LR11X0_STANDBY_RC, true);
|
||||
|
||||
radio->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL);
|
||||
|
||||
// calibrate(0x3F) defaults image calibration to 902-928MHz band.
|
||||
// Re-calibrate for the actual operating frequency (band=4MHz matches RadioLib default).
|
||||
radio->calibrateImageRejection(freqMHz - 4.0f, freqMHz + 4.0f);
|
||||
|
||||
#ifdef RX_BOOSTED_GAIN
|
||||
radio->setRxBoostedGainMode(RX_BOOSTED_GAIN);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -53,13 +53,24 @@ void RadioLibWrapper::triggerNoiseFloorCalibrate(int threshold) {
|
|||
}
|
||||
}
|
||||
|
||||
void RadioLibWrapper::doResetAGC() {
|
||||
_radio->sleep(); // warm sleep to reset analog frontend
|
||||
}
|
||||
|
||||
void RadioLibWrapper::resetAGC() {
|
||||
// make sure we're not mid-receive of packet!
|
||||
if ((state & STATE_INT_READY) != 0 || isReceivingPacket()) return;
|
||||
|
||||
// NOTE: according to higher powers, just issuing RadioLib's startReceive() will reset the AGC.
|
||||
// revisit this if a better impl is discovered.
|
||||
doResetAGC();
|
||||
state = STATE_IDLE; // trigger a startReceive()
|
||||
|
||||
// Reset noise floor sampling so it reconverges from scratch.
|
||||
// Without this, a stuck _noise_floor of -120 makes the sampling threshold
|
||||
// too low (-106) to accept normal samples (~-105), self-reinforcing the
|
||||
// stuck value even after the receiver has recovered.
|
||||
_noise_floor = 0;
|
||||
_num_floor_samples = 0;
|
||||
_floor_sample_sum = 0;
|
||||
}
|
||||
|
||||
void RadioLibWrapper::loop() {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ protected:
|
|||
void startRecv();
|
||||
float packetScoreInt(float snr, int sf, int packet_len);
|
||||
virtual bool isReceivingPacket() =0;
|
||||
virtual void doResetAGC();
|
||||
|
||||
public:
|
||||
RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; }
|
||||
|
|
|
|||
37
src/helpers/radiolib/SX126xReset.h
Normal file
37
src/helpers/radiolib/SX126xReset.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include <RadioLib.h>
|
||||
|
||||
// Full receiver reset for all SX126x-family chips (SX1262, SX1268, LLCC68, STM32WLx).
|
||||
// Warm sleep powers down analog, Calibrate(0x7F) refreshes ADC/PLL/image calibration,
|
||||
// then re-applies RX settings that calibration may reset.
|
||||
inline void sx126xResetAGC(SX126x* radio) {
|
||||
radio->sleep(true);
|
||||
radio->standby(RADIOLIB_SX126X_STANDBY_RC, true);
|
||||
|
||||
uint8_t calData = RADIOLIB_SX126X_CALIBRATE_ALL;
|
||||
radio->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, &calData, 1, true, false);
|
||||
radio->mod->hal->delay(5);
|
||||
uint32_t start = millis();
|
||||
while (radio->mod->hal->digitalRead(radio->mod->getGpio())) {
|
||||
if (millis() - start > 50) break;
|
||||
radio->mod->hal->yield();
|
||||
}
|
||||
|
||||
// Calibrate(0x7F) defaults image calibration to 902-928MHz band.
|
||||
// Re-calibrate for the actual operating frequency.
|
||||
radio->calibrateImage(radio->freqMHz);
|
||||
|
||||
#ifdef SX126X_DIO2_AS_RF_SWITCH
|
||||
radio->setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
|
||||
#endif
|
||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||
radio->setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
|
||||
#endif
|
||||
#ifdef SX126X_REGISTER_PATCH
|
||||
uint8_t r_data = 0;
|
||||
radio->readRegister(0x8B5, &r_data, 1);
|
||||
r_data |= 0x01;
|
||||
radio->writeRegister(0x8B5, &r_data, 1);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -683,7 +683,7 @@ void EnvironmentSensorManager::start_gps() {
|
|||
_location->begin();
|
||||
_location->reset();
|
||||
|
||||
#ifndef PIN_GPS_RESET
|
||||
#ifndef PIN_GPS_EN
|
||||
MESH_DEBUG_PRINTLN("Start GPS is N/A on this board. Actual GPS state unchanged");
|
||||
#endif
|
||||
}
|
||||
|
|
@ -707,7 +707,9 @@ void EnvironmentSensorManager::loop() {
|
|||
static long next_gps_update = 0;
|
||||
|
||||
#if ENV_INCLUDE_GPS
|
||||
_location->loop();
|
||||
if (gps_active) {
|
||||
_location->loop();
|
||||
}
|
||||
if (millis() > next_gps_update) {
|
||||
|
||||
if(gps_active){
|
||||
|
|
|
|||
|
|
@ -79,7 +79,10 @@ public :
|
|||
if (_pin_en != -1) {
|
||||
digitalWrite(_pin_en, !PIN_GPS_EN_ACTIVE);
|
||||
}
|
||||
if (_peripher_power) _peripher_power->release();
|
||||
if (_pin_reset != -1) {
|
||||
digitalWrite(_pin_reset, GPS_RESET_FORCE);
|
||||
}
|
||||
if (_peripher_power) _peripher_power->release();
|
||||
}
|
||||
|
||||
bool isEnabled() override {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue