mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge branch 'dev' into faketec-support
This commit is contained in:
commit
74ec702136
28 changed files with 1641 additions and 1199 deletions
|
|
@ -115,6 +115,7 @@ void Dispatcher::checkRecv() {
|
|||
} 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);
|
||||
}
|
||||
|
|
@ -129,7 +130,7 @@ void Dispatcher::checkRecv() {
|
|||
Serial.print(getLogDateTime());
|
||||
Serial.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d",
|
||||
2 + pkt->path_len + pkt->payload_len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len,
|
||||
(int)_radio->getLastSNR(), (int)_radio->getLastRSSI(), (int)(score*1000));
|
||||
(int)pkt->getSNR(), (int)_radio->getLastRSSI(), (int)(score*1000));
|
||||
|
||||
static uint8_t packet_hash[MAX_HASH_SIZE];
|
||||
pkt->calculatePacketHash(packet_hash);
|
||||
|
|
@ -233,6 +234,7 @@ Packet* Dispatcher::obtainNewPacket() {
|
|||
n_full_events++;
|
||||
} else {
|
||||
pkt->payload_len = pkt->path_len = 0;
|
||||
pkt->_snr = 0;
|
||||
}
|
||||
return pkt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <string.h>
|
||||
#define ED25519_NO_SEED 1
|
||||
#include <ed_25519.h>
|
||||
#include <Ed25519.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
|
|
@ -14,7 +15,12 @@ Identity::Identity(const char* pub_hex) {
|
|||
}
|
||||
|
||||
bool Identity::verify(const uint8_t* sig, const uint8_t* message, int msg_len) const {
|
||||
#if 0
|
||||
// NOTE: memory corruption bug was found in this function!!
|
||||
return ed25519_verify(sig, message, msg_len, pub_key);
|
||||
#else
|
||||
return Ed25519::verify(sig, this->pub_key, message, msg_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Identity::readFrom(Stream& s) {
|
||||
|
|
|
|||
64
src/Mesh.cpp
64
src/Mesh.cpp
|
|
@ -41,6 +41,30 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||
return ACTION_RELEASE;
|
||||
}
|
||||
|
||||
if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) {
|
||||
if (pkt->path_len < MAX_PATH_SIZE) {
|
||||
uint8_t i = 0;
|
||||
uint32_t trace_tag;
|
||||
memcpy(&trace_tag, &pkt->payload[i], 4); i += 4;
|
||||
uint32_t auth_code;
|
||||
memcpy(&auth_code, &pkt->payload[i], 4); i += 4;
|
||||
uint8_t flags = pkt->payload[i++];
|
||||
|
||||
uint8_t len = pkt->payload_len - i;
|
||||
if (pkt->path_len >= len) { // TRACE has reached end of given path
|
||||
onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len);
|
||||
} else if (self_id.isHashMatch(&pkt->payload[i + pkt->path_len]) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) {
|
||||
// append SNR (Not hash!)
|
||||
pkt->path[pkt->path_len] = (int8_t) (pkt->getSNR()*4);
|
||||
pkt->path_len += PATH_HASH_SIZE;
|
||||
|
||||
uint32_t d = getDirectRetransmitDelay(pkt);
|
||||
return ACTION_RETRANSMIT_DELAYED(5, d); // schedule with priority 5 (for now), maybe make configurable?
|
||||
}
|
||||
}
|
||||
return ACTION_RELEASE;
|
||||
}
|
||||
|
||||
if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) {
|
||||
if (self_id.isHashMatch(pkt->path) && allowPacketForward(pkt)) {
|
||||
if (_tables->hasSeen(pkt)) return ACTION_RELEASE; // don't retransmit!
|
||||
|
|
@ -79,7 +103,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||
uint8_t src_hash = pkt->payload[i++];
|
||||
|
||||
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
||||
if (i + 2 >= pkt->payload_len) {
|
||||
if (i + CIPHER_MAC_SIZE >= pkt->payload_len) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
||||
} else if (!_tables->hasSeen(pkt)) {
|
||||
// NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins.
|
||||
|
|
@ -333,7 +357,7 @@ Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret,
|
|||
|
||||
Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len) {
|
||||
if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE) {
|
||||
if (data_len + 2 + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL;
|
||||
if (data_len + CIPHER_MAC_SIZE + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL;
|
||||
} else {
|
||||
return NULL; // invalid type
|
||||
}
|
||||
|
|
@ -433,7 +457,28 @@ Packet* Mesh::createRawData(const uint8_t* data, size_t len) {
|
|||
return packet;
|
||||
}
|
||||
|
||||
Packet* Mesh::createTrace(uint32_t tag, uint32_t auth_code, uint8_t flags) {
|
||||
Packet* packet = obtainNewPacket();
|
||||
if (packet == NULL) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::createTrace(): error, packet pool empty", getLogDateTime());
|
||||
return NULL;
|
||||
}
|
||||
packet->header = (PAYLOAD_TYPE_TRACE << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later
|
||||
|
||||
memcpy(packet->payload, &tag, 4);
|
||||
memcpy(&packet->payload[4], &auth_code, 4);
|
||||
packet->payload[8] = flags;
|
||||
packet->payload_len = 9; // NOTE: path will be appended to payload[] later
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) {
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime());
|
||||
return;
|
||||
}
|
||||
|
||||
packet->header &= ~PH_ROUTE_MASK;
|
||||
packet->header |= ROUTE_TYPE_FLOOD;
|
||||
packet->path_len = 0;
|
||||
|
|
@ -455,11 +500,20 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin
|
|||
packet->header &= ~PH_ROUTE_MASK;
|
||||
packet->header |= ROUTE_TYPE_DIRECT;
|
||||
|
||||
memcpy(packet->path, path, packet->path_len = path_len);
|
||||
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);
|
||||
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);
|
||||
pri = 0;
|
||||
}
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
|
||||
sendPacket(packet, 0, delay_millis);
|
||||
sendPacket(packet, pri, delay_millis);
|
||||
}
|
||||
|
||||
void Mesh::sendZeroHop(Packet* packet, uint32_t delay_millis) {
|
||||
|
|
|
|||
15
src/Mesh.h
15
src/Mesh.h
|
|
@ -100,9 +100,22 @@ protected:
|
|||
* \param type one of: PAYLOAD_TYPE_TXT_MSG, PAYLOAD_TYPE_REQ, PAYLOAD_TYPE_RESPONSE
|
||||
* \param sender_idx index of peer, [0..n) where n is what searchPeersByHash() returned
|
||||
* \param secret the pre-calculated shared-secret (handy for sending response packet)
|
||||
* \param data decrypted data from payload
|
||||
*/
|
||||
virtual void onPeerDataRecv(Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) { }
|
||||
|
||||
/**
|
||||
* \brief A TRACE packet has been received. (and has reached the end of its given path)
|
||||
* NOTE: this may have been initiated by another node.
|
||||
* \param tag a random (unique-ish) tag set by initiator
|
||||
* \param auth_code a code to authenticate the packet
|
||||
* \param flags zero for now
|
||||
* \param path_snrs single byte SNR*4 for each hop in the path
|
||||
* \param path_hashes hashes if each repeater in the path
|
||||
* \param path_len length of the path_snrs[] and path_hashes[] arrays
|
||||
*/
|
||||
virtual void onTraceRecv(Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) { }
|
||||
|
||||
/**
|
||||
* \brief A path TO peer (sender_idx) has been received. (also with optional 'extra' data encoded)
|
||||
* NOTE: these can be received multiple times (per sender), via differen routes
|
||||
|
|
@ -182,6 +195,7 @@ public:
|
|||
Packet* 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);
|
||||
Packet* createPathReturn(const Identity& dest, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len);
|
||||
Packet* createRawData(const uint8_t* data, size_t len);
|
||||
Packet* createTrace(uint32_t tag, uint32_t auth_code, uint8_t flags = 0);
|
||||
|
||||
/**
|
||||
* \brief send a locally-generated Packet with flood routing
|
||||
|
|
@ -197,6 +211,7 @@ public:
|
|||
* \brief send a locally-generated Packet to just neigbor nodes (zero hops)
|
||||
*/
|
||||
void sendZeroHop(Packet* packet, uint32_t delay_millis=0);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ Packet::Packet() {
|
|||
payload_len = 0;
|
||||
}
|
||||
|
||||
|
||||
void Packet::calculatePacketHash(uint8_t* hash) const {
|
||||
SHA256 sha;
|
||||
uint8_t t = getPayloadType();
|
||||
sha.update(&t, 1);
|
||||
if (t == PAYLOAD_TYPE_TRACE) {
|
||||
sha.update(&path_len, sizeof(path_len)); // CAVEAT: TRACE packets can revisit same node on return path
|
||||
}
|
||||
sha.update(payload, payload_len);
|
||||
sha.finalize(hash, MAX_HASH_SIZE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace mesh {
|
|||
#define PAYLOAD_TYPE_GRP_DATA 0x06 // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: timestamp, blob)
|
||||
#define PAYLOAD_TYPE_ANON_REQ 0x07 // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
|
||||
#define PAYLOAD_TYPE_PATH 0x08 // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
|
||||
#define PAYLOAD_TYPE_TRACE 0x09 // trace a path, collecting SNI for each hop
|
||||
//...
|
||||
#define PAYLOAD_TYPE_RAW_CUSTOM 0x0F // custom packet as raw bytes, for applications with custom encryption, payloads, etc
|
||||
|
||||
|
|
@ -44,6 +45,7 @@ public:
|
|||
uint16_t payload_len, path_len;
|
||||
uint8_t path[MAX_PATH_SIZE];
|
||||
uint8_t payload[MAX_PACKET_PAYLOAD];
|
||||
int8_t _snr;
|
||||
|
||||
/**
|
||||
* \brief calculate the hash of payload + type
|
||||
|
|
@ -72,6 +74,8 @@ public:
|
|||
void markDoNotRetransmit() { header = 0xFF; }
|
||||
bool isMarkedDoNotRetransmit() const { return header == 0xFF; }
|
||||
|
||||
float getSNR() const { return ((float)_snr) / 4.0f; }
|
||||
|
||||
/**
|
||||
* \brief save entire packet as a blob
|
||||
* \param dest (OUT) destination buffer (assumed to be MAX_MTU_SIZE)
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
|
|||
data[len] = 0; // need to make a C string again, with null terminator
|
||||
|
||||
if (flags == TXT_TYPE_PLAIN) {
|
||||
onMessageRecv(from, packet->isRouteFlood() ? packet->path_len : 0xFF, timestamp, (const char *) &data[5]); // let UI know
|
||||
onMessageRecv(from, packet, timestamp, (const char *) &data[5]); // let UI know
|
||||
|
||||
uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it
|
||||
mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 5 + strlen((char *)&data[5]), from.id.pub_key, PUB_KEY_SIZE);
|
||||
|
|
@ -126,7 +126,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
|
|||
}
|
||||
}
|
||||
} else if (flags == TXT_TYPE_CLI_DATA) {
|
||||
onCommandDataRecv(from, packet->isRouteFlood() ? packet->path_len : 0xFF, timestamp, (const char *) &data[5]); // let UI know
|
||||
onCommandDataRecv(from, packet, timestamp, (const char *) &data[5]); // let UI know
|
||||
// NOTE: no ack expected for CLI_DATA replies
|
||||
|
||||
if (packet->isRouteFlood()) {
|
||||
|
|
@ -138,7 +138,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
|
|||
if (timestamp > from.sync_since) { // make sure 'sync_since' is up-to-date
|
||||
from.sync_since = timestamp;
|
||||
}
|
||||
onSignedMessageRecv(from, packet->isRouteFlood() ? packet->path_len : 0xFF, timestamp, &data[5], (const char *) &data[9]); // let UI know
|
||||
onSignedMessageRecv(from, packet, timestamp, &data[5], (const char *) &data[9]); // let UI know
|
||||
|
||||
uint32_t ack_hash; // calc truncated hash of the message timestamp + text + OUR pub_key, to prove to sender that we got it
|
||||
mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 9 + strlen((char *)&data[9]), self_id.pub_key, PUB_KEY_SIZE);
|
||||
|
|
@ -222,7 +222,7 @@ void BaseChatMesh::onGroupDataRecv(mesh::Packet* packet, uint8_t type, const mes
|
|||
data[len] = 0; // need to make a C string again, with null terminator
|
||||
|
||||
// notify UI of this new message
|
||||
onChannelMessageRecv(channel, packet->isRouteFlood() ? packet->path_len : -1, timestamp, (const char *) &data[5]); // let UI know
|
||||
onChannelMessageRecv(channel, packet, timestamp, (const char *) &data[5]); // let UI know
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,13 +106,13 @@ protected:
|
|||
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new) = 0;
|
||||
virtual bool processAck(const uint8_t *data) = 0;
|
||||
virtual void onContactPathUpdated(const ContactInfo& contact) = 0;
|
||||
virtual void onMessageRecv(const ContactInfo& contact, uint8_t path_len, uint32_t sender_timestamp, const char *text) = 0;
|
||||
virtual void onCommandDataRecv(const ContactInfo& contact, uint8_t path_len, uint32_t sender_timestamp, const char *text) = 0;
|
||||
virtual void onSignedMessageRecv(const ContactInfo& contact, uint8_t path_len, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) = 0;
|
||||
virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0;
|
||||
virtual void onCommandDataRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0;
|
||||
virtual void onSignedMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) = 0;
|
||||
virtual uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const = 0;
|
||||
virtual uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const = 0;
|
||||
virtual void onSendTimeout() = 0;
|
||||
virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, int in_path_len, uint32_t timestamp, const char *text) = 0;
|
||||
virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) = 0;
|
||||
virtual void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) = 0;
|
||||
|
||||
// storage concepts, for sub-classes to override/implement
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class CustomLLCC68 : public LLCC68 {
|
|||
CustomLLCC68(Module *mod) : LLCC68(mod) { }
|
||||
|
||||
bool isReceiving() {
|
||||
uint16_t irq = getIrqStatus();
|
||||
uint16_t irq = getIrqFlags();
|
||||
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
}
|
||||
|
|
|
|||
82
src/helpers/TBeamBoard.h
Normal file
82
src/helpers/TBeamBoard.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Arduino.h>
|
||||
#include "XPowersLib.h"
|
||||
|
||||
// Defined using AXP2102
|
||||
#define XPOWERS_CHIP_AXP2101
|
||||
|
||||
// LoRa radio module pins for TBeam
|
||||
#define P_LORA_DIO_0 26
|
||||
#define P_LORA_DIO_2 32
|
||||
#define P_LORA_DIO_1 33
|
||||
#define P_LORA_NSS 18
|
||||
#define P_LORA_RESET 14
|
||||
#define P_LORA_BUSY RADIOLIB_NC
|
||||
#define P_LORA_SCLK 5
|
||||
#define P_LORA_MISO 19
|
||||
#define P_LORA_MOSI 27
|
||||
|
||||
// built-ins
|
||||
//#define PIN_VBAT_READ 37
|
||||
//#define PIN_LED_BUILTIN 25
|
||||
|
||||
#include "ESP32Board.h"
|
||||
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class TBeamBoard : public ESP32Board {
|
||||
XPowersAXP2101 power;
|
||||
|
||||
public:
|
||||
void begin() {
|
||||
ESP32Board::begin();
|
||||
|
||||
power.setALDO2Voltage(3300);
|
||||
power.enableALDO2();
|
||||
|
||||
esp_reset_reason_t reason = esp_reset_reason();
|
||||
if (reason == ESP_RST_DEEPSLEEP) {
|
||||
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
|
||||
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
|
||||
startup_reason = BD_STARTUP_RX_PACKET;
|
||||
}
|
||||
|
||||
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
|
||||
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
|
||||
}
|
||||
}
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "LilyGo T-Beam";
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue