Merge upstream/dev into develop

此提交包含在:
Jared Dohrman
2026-04-17 17:54:47 +10:00
當前提交 e05c9bc09c
共有 37 個檔案被更改,包括 2059 行新增629 行删除
檔案差異因為檔案過大而無法顯示 載入差異
+29 -7
查看文件
@@ -230,17 +230,37 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
file.read((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86 file.read((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86
file.read((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87 file.read((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87
file.read((uint8_t *)&_prefs.autoadd_max_hops, sizeof(_prefs.autoadd_max_hops)); // 88 file.read((uint8_t *)&_prefs.autoadd_max_hops, sizeof(_prefs.autoadd_max_hops)); // 88
file.read((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 file.read((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89
if (file.available() >= (int)sizeof(_prefs.wifi_powersave)) {
const int wifi_bytes = sizeof(_prefs.wifi_powersave) + sizeof(_prefs.wifi_ssid) + sizeof(_prefs.wifi_pwd);
const int scope_bytes = sizeof(_prefs.default_scope_name) + sizeof(_prefs.default_scope_key);
const int remaining = file.available();
if (remaining >= wifi_bytes + scope_bytes) {
file.read((uint8_t *)&_prefs.wifi_powersave, sizeof(_prefs.wifi_powersave)); // 90 file.read((uint8_t *)&_prefs.wifi_powersave, sizeof(_prefs.wifi_powersave)); // 90
}
if (file.available() >= (int)sizeof(_prefs.wifi_ssid)) {
file.read((uint8_t *)_prefs.wifi_ssid, sizeof(_prefs.wifi_ssid)); // 91 file.read((uint8_t *)_prefs.wifi_ssid, sizeof(_prefs.wifi_ssid)); // 91
_prefs.wifi_ssid[sizeof(_prefs.wifi_ssid) - 1] = 0; _prefs.wifi_ssid[sizeof(_prefs.wifi_ssid) - 1] = 0;
}
if (file.available() >= (int)sizeof(_prefs.wifi_pwd)) {
file.read((uint8_t *)_prefs.wifi_pwd, sizeof(_prefs.wifi_pwd)); // 124 file.read((uint8_t *)_prefs.wifi_pwd, sizeof(_prefs.wifi_pwd)); // 124
_prefs.wifi_pwd[sizeof(_prefs.wifi_pwd) - 1] = 0; _prefs.wifi_pwd[sizeof(_prefs.wifi_pwd) - 1] = 0;
file.read((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 189
_prefs.default_scope_name[sizeof(_prefs.default_scope_name) - 1] = 0;
file.read((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 220
} else if (remaining >= scope_bytes) {
file.read((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 90
_prefs.default_scope_name[sizeof(_prefs.default_scope_name) - 1] = 0;
file.read((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 121
} else {
if (file.available() >= (int)sizeof(_prefs.wifi_powersave)) {
file.read((uint8_t *)&_prefs.wifi_powersave, sizeof(_prefs.wifi_powersave)); // 90
}
if (file.available() >= (int)sizeof(_prefs.wifi_ssid)) {
file.read((uint8_t *)_prefs.wifi_ssid, sizeof(_prefs.wifi_ssid)); // 91
_prefs.wifi_ssid[sizeof(_prefs.wifi_ssid) - 1] = 0;
}
if (file.available() >= (int)sizeof(_prefs.wifi_pwd)) {
file.read((uint8_t *)_prefs.wifi_pwd, sizeof(_prefs.wifi_pwd)); // 124
_prefs.wifi_pwd[sizeof(_prefs.wifi_pwd) - 1] = 0;
}
} }
file.close(); file.close();
@@ -279,10 +299,12 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86 file.write((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86
file.write((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87 file.write((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87
file.write((uint8_t *)&_prefs.autoadd_max_hops, sizeof(_prefs.autoadd_max_hops)); // 88 file.write((uint8_t *)&_prefs.autoadd_max_hops, sizeof(_prefs.autoadd_max_hops)); // 88
file.write((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 file.write((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89
file.write((uint8_t *)&_prefs.wifi_powersave, sizeof(_prefs.wifi_powersave)); // 90 file.write((uint8_t *)&_prefs.wifi_powersave, sizeof(_prefs.wifi_powersave)); // 90
file.write((uint8_t *)_prefs.wifi_ssid, sizeof(_prefs.wifi_ssid)); // 91 file.write((uint8_t *)_prefs.wifi_ssid, sizeof(_prefs.wifi_ssid)); // 91
file.write((uint8_t *)_prefs.wifi_pwd, sizeof(_prefs.wifi_pwd)); // 124 file.write((uint8_t *)_prefs.wifi_pwd, sizeof(_prefs.wifi_pwd)); // 124
file.write((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 189
file.write((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 220
file.close(); file.close();
} }
+62 -15
查看文件
@@ -53,7 +53,7 @@
#define CMD_SEND_BINARY_REQ 50 #define CMD_SEND_BINARY_REQ 50
#define CMD_FACTORY_RESET 51 #define CMD_FACTORY_RESET 51
#define CMD_SEND_PATH_DISCOVERY_REQ 52 #define CMD_SEND_PATH_DISCOVERY_REQ 52
#define CMD_SET_FLOOD_SCOPE 54 // v8+ #define CMD_SET_FLOOD_SCOPE_KEY 54 // v8+
#define CMD_SEND_CONTROL_DATA 55 // v8+ #define CMD_SEND_CONTROL_DATA 55 // v8+
#define CMD_GET_STATS 56 // v8+, second byte is stats type #define CMD_GET_STATS 56 // v8+, second byte is stats type
#define CMD_SEND_ANON_REQ 57 #define CMD_SEND_ANON_REQ 57
@@ -62,6 +62,8 @@
#define CMD_GET_ALLOWED_REPEAT_FREQ 60 #define CMD_GET_ALLOWED_REPEAT_FREQ 60
#define CMD_SET_PATH_HASH_MODE 61 #define CMD_SET_PATH_HASH_MODE 61
#define CMD_SEND_CHANNEL_DATA 62 #define CMD_SEND_CHANNEL_DATA 62
#define CMD_SET_DEFAULT_FLOOD_SCOPE 63
#define CMD_GET_DEFAULT_FLOOD_SCOPE 64
// Stats sub-types for CMD_GET_STATS // Stats sub-types for CMD_GET_STATS
#define STATS_TYPE_CORE 0 #define STATS_TYPE_CORE 0
@@ -96,6 +98,7 @@
#define RESP_CODE_AUTOADD_CONFIG 25 #define RESP_CODE_AUTOADD_CONFIG 25
#define RESP_ALLOWED_REPEAT_FREQ 26 #define RESP_ALLOWED_REPEAT_FREQ 26
#define RESP_CODE_CHANNEL_DATA_RECV 27 #define RESP_CODE_CHANNEL_DATA_RECV 27
#define RESP_CODE_DEFAULT_FLOOD_SCOPE 28
#define MAX_CHANNEL_DATA_LENGTH (MAX_FRAME_SIZE - 9) #define MAX_CHANNEL_DATA_LENGTH (MAX_FRAME_SIZE - 9)
@@ -548,27 +551,32 @@ bool MyMesh::allowPacketForward(const mesh::Packet* packet) {
return _prefs.client_repeat != 0; return _prefs.client_repeat != 0;
} }
void MyMesh::sendFloodScoped(const ContactInfo& recipient, mesh::Packet* pkt, uint32_t delay_millis) { void MyMesh::sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis) {
// TODO: dynamic send_scope, depending on recipient and current 'home' Region if (scope.isNull()) {
if (send_scope.isNull()) {
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1);
} else { } else {
uint16_t codes[2]; uint16_t codes[2];
codes[0] = send_scope.calcTransportCode(pkt); codes[0] = scope.calcTransportCode(pkt);
codes[1] = 0; // REVISIT: set to 'home' Region, for sender/return region? codes[1] = 0; // REVISIT: set to 'home' Region, for sender/return region?
sendFlood(pkt, codes, delay_millis, _prefs.path_hash_mode + 1); sendFlood(pkt, codes, delay_millis, _prefs.path_hash_mode + 1);
} }
} }
void MyMesh::sendFloodScoped(const ContactInfo& recipient, mesh::Packet* pkt, uint32_t delay_millis) {
// TODO: dynamic send_scope, depending on recipient and current 'home' Region
TransportKey default_scope;
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
auto scope = send_scope.isNull() ? &default_scope : &send_scope;
sendFloodScoped(*scope, pkt, delay_millis);
}
void MyMesh::sendFloodScoped(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t delay_millis) { void MyMesh::sendFloodScoped(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t delay_millis) {
// TODO: have per-channel send_scope // TODO: have per-channel send_scope
if (send_scope.isNull()) { TransportKey default_scope;
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
} else {
uint16_t codes[2]; auto scope = send_scope.isNull() ? &default_scope : &send_scope;
codes[0] = send_scope.calcTransportCode(pkt); sendFloodScoped(*scope, pkt, delay_millis);
codes[1] = 0; // REVISIT: set to 'home' Region, for sender/return region?
sendFlood(pkt, codes, delay_millis, _prefs.path_hash_mode + 1);
}
} }
void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp,
@@ -973,6 +981,17 @@ void MyMesh::begin(bool has_display) {
strcpy(_prefs.node_name, pub_key_hex); strcpy(_prefs.node_name, pub_key_hex);
#endif #endif
// if build provides default-scope, init with that
#ifdef DEFAULT_FLOOD_SCOPE_NAME
strcpy(_prefs.default_scope_name, DEFAULT_FLOOD_SCOPE_NAME);
{
TransportKeyStore temp;
TransportKey key;
temp.getAutoKeyFor(0, "#" DEFAULT_FLOOD_SCOPE_NAME, key);
memcpy(_prefs.default_scope_key, key.key, sizeof(key.key));
}
#endif
// load persisted prefs // load persisted prefs
_store->loadPrefs(_prefs, sensors.node_lat, sensors.node_lon); _store->loadPrefs(_prefs, sensors.node_lat, sensors.node_lon);
@@ -1290,7 +1309,9 @@ void MyMesh::handleCmdFrame(size_t len) {
if (pkt) { if (pkt) {
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
unsigned long delay_millis = 0; unsigned long delay_millis = 0;
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); TransportKey default_scope;
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
sendFloodScoped(default_scope, pkt, delay_millis);
} else { } else {
sendZeroHop(pkt); sendZeroHop(pkt);
} }
@@ -1942,13 +1963,39 @@ void MyMesh::handleCmdFrame(size_t len) {
} else { } else {
writeErrFrame(ERR_CODE_FILE_IO_ERROR); writeErrFrame(ERR_CODE_FILE_IO_ERROR);
} }
} else if (cmd_frame[0] == CMD_SET_FLOOD_SCOPE && len >= 2 && cmd_frame[1] == 0) { } else if (cmd_frame[0] == CMD_SET_FLOOD_SCOPE_KEY && len >= 2 && cmd_frame[1] == 0) {
if (len >= 2 + 16) { if (len >= 2 + 16) {
memcpy(send_scope.key, &cmd_frame[2], sizeof(send_scope.key)); // set curr scope TransportKey memcpy(send_scope.key, &cmd_frame[2], sizeof(send_scope.key)); // set curr scope TransportKey
} else { } else {
memset(send_scope.key, 0, sizeof(send_scope.key)); // set scope to null memset(send_scope.key, 0, sizeof(send_scope.key)); // set scope to null
} }
writeOKFrame(); writeOKFrame();
} else if (cmd_frame[0] == CMD_SET_DEFAULT_FLOOD_SCOPE && len >= 1) {
if (len >= 1+31+16) {
int n = strlen((char *) &cmd_frame[1]);
if (n > 0 && n < 31) {
strcpy(_prefs.default_scope_name, (char *) &cmd_frame[1]);
memcpy(_prefs.default_scope_key, &cmd_frame[1+31], 16);
savePrefs();
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else {
memset(_prefs.default_scope_name, 0, sizeof(_prefs.default_scope_name)); // set default scope to null
memset(_prefs.default_scope_key, 0, sizeof(_prefs.default_scope_key));
savePrefs();
writeOKFrame();
}
} else if (cmd_frame[0] == CMD_GET_DEFAULT_FLOOD_SCOPE) {
out_frame[0] = RESP_CODE_DEFAULT_FLOOD_SCOPE;
if (strlen(_prefs.default_scope_name) > 0) {
memcpy(&out_frame[1], _prefs.default_scope_name, 31);
memcpy(&out_frame[1+31], _prefs.default_scope_key, 16);
_serial->writeFrame(out_frame, 1+31+16);
} else {
_serial->writeFrame(out_frame, 1); // no name or key means null
}
} else if (cmd_frame[0] == CMD_SEND_CONTROL_DATA && len >= 2 && (cmd_frame[1] & 0x80) != 0) { } else if (cmd_frame[0] == CMD_SEND_CONTROL_DATA && len >= 2 && (cmd_frame[1] & 0x80) != 0) {
auto resp = createControlData(&cmd_frame[1], len - 1); auto resp = createControlData(&cmd_frame[1], len - 1);
if (resp) { if (resp) {
+2 -1
查看文件
@@ -5,7 +5,7 @@
#include "AbstractUITask.h" #include "AbstractUITask.h"
/*------------ Frame Protocol --------------*/ /*------------ Frame Protocol --------------*/
#define FIRMWARE_VER_CODE 10 #define FIRMWARE_VER_CODE 11
#ifndef FIRMWARE_BUILD_DATE #ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "20 Mar 2026" #define FIRMWARE_BUILD_DATE "20 Mar 2026"
@@ -117,6 +117,7 @@ protected:
bool filterRecvFloodPacket(mesh::Packet* packet) override; bool filterRecvFloodPacket(mesh::Packet* packet) override;
bool allowPacketForward(const mesh::Packet* packet) override; bool allowPacketForward(const mesh::Packet* packet) override;
void sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis);
void sendFloodScoped(const ContactInfo& recipient, mesh::Packet* pkt, uint32_t delay_millis=0) override; void sendFloodScoped(const ContactInfo& recipient, mesh::Packet* pkt, uint32_t delay_millis=0) override;
void sendFloodScoped(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t delay_millis=0) override; void sendFloodScoped(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t delay_millis=0) override;
+2
查看文件
@@ -35,4 +35,6 @@ struct NodePrefs { // persisted to file
uint8_t wifi_powersave; // 0 = none, 1 = min, 2 = max uint8_t wifi_powersave; // 0 = none, 1 = min, 2 = max
char wifi_ssid[33]; char wifi_ssid[33];
char wifi_pwd[65]; char wifi_pwd[65];
char default_scope_name[31];
uint8_t default_scope_key[16];
}; };
+76 -110
查看文件
@@ -537,6 +537,19 @@ bool MyMesh::isLooped(const mesh::Packet* packet, const uint8_t max_counters[])
return n >= max_counters[hash_size]; return n >= max_counters[hash_size];
} }
void MyMesh::sendFloodReply(mesh::Packet* packet, unsigned long delay_millis, uint8_t path_hash_size) {
if (recv_pkt_region && !recv_pkt_region->isWildcard()) { // if _request_ packet scope is known, send reply with same scope
TransportKey scope;
if (region_map.getTransportKeysFor(*recv_pkt_region, &scope, 1) > 0) {
sendFloodScoped(scope, packet, delay_millis, path_hash_size);
} else {
sendFlood(packet, delay_millis, path_hash_size); // send un-scoped
}
} else {
sendFlood(packet, delay_millis, path_hash_size); // send un-scoped
}
}
bool MyMesh::allowPacketForward(const mesh::Packet *packet) { bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
if (_prefs.disable_fwd) return false; if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->getPathHashCount() >= _prefs.flood_max) return false; if (packet->isRouteFlood() && packet->getPathHashCount() >= _prefs.flood_max) return false;
@@ -709,10 +722,10 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len, mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else if (reply_path_len < 0) { } else if (reply_path_len < 0) {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len); mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
if (reply) sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); if (reply) sendFloodReply(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len); mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
uint8_t path_len = ((reply_path_hash_size - 1) << 6) | (reply_path_len & 63); uint8_t path_len = ((reply_path_hash_size - 1) << 6) | (reply_path_len & 63);
@@ -785,7 +798,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len, mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet *reply = mesh::Packet *reply =
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len); createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len);
@@ -793,7 +806,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); sendFloodReply(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -824,7 +837,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
mesh::Packet *ack = createAck(ack_hash); mesh::Packet *ack = createAck(ack_hash);
if (ack) { if (ack) {
if (client->out_path_len == OUT_PATH_UNKNOWN) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(ack, TXT_ACK_DELAY, packet->getPathHashSize()); sendFloodReply(ack, TXT_ACK_DELAY, packet->getPathHashSize());
} else { } else {
sendDirect(ack, client->out_path, client->out_path_len, TXT_ACK_DELAY); sendDirect(ack, client->out_path, client->out_path_len, TXT_ACK_DELAY);
} }
@@ -852,7 +865,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len); auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len);
if (reply) { if (reply) {
if (client->out_path_len == OUT_PATH_UNKNOWN) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize()); sendFloodReply(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize());
} else { } else {
sendDirect(reply, client->out_path, client->out_path_len, CLI_REPLY_DELAY_MILLIS); sendDirect(reply, client->out_path, client->out_path_len, CLI_REPLY_DELAY_MILLIS);
} }
@@ -962,7 +975,9 @@ void MyMesh::sendNodeDiscoverReq() {
MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondClock &ms, mesh::RNG &rng, MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondClock &ms, mesh::RNG &rng,
mesh::RTCClock &rtc, mesh::MeshTables &tables) mesh::RTCClock &rtc, mesh::MeshTables &tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables), : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
_cli(board, rtc, sensors, acl, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4), region_map(key_store), temp_map(key_store), region_map(key_store), temp_map(key_store),
_cli(board, rtc, sensors, region_map, acl, &_prefs, this),
telemetry(MAX_PACKET_PAYLOAD - 4),
discover_limiter(4, 120), // max 4 every 2 minutes discover_limiter(4, 120), // max 4 every 2 minutes
anon_limiter(4, 180) // max 4 every 3 minutes anon_limiter(4, 180) // max 4 every 3 minutes
#if defined(WITH_RS232_BRIDGE) #if defined(WITH_RS232_BRIDGE)
@@ -1039,6 +1054,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
pending_discover_tag = 0; pending_discover_tag = 0;
pending_discover_until = 0; pending_discover_until = 0;
memset(default_scope.key, 0, sizeof(default_scope.key));
} }
void MyMesh::begin(FILESYSTEM *fs, ArchiveStorage* archive) { void MyMesh::begin(FILESYSTEM *fs, ArchiveStorage* archive) {
@@ -1052,6 +1069,26 @@ void MyMesh::begin(FILESYSTEM *fs, ArchiveStorage* archive) {
// TODO: key_store.begin(); // TODO: key_store.begin();
region_map.load(_fs); region_map.load(_fs);
// establish default-scope
{
RegionEntry* r = region_map.getDefaultRegion();
if (r) {
region_map.getTransportKeysFor(*r, &default_scope, 1);
} else {
#ifdef DEFAULT_FLOOD_SCOPE_NAME
r = region_map.findByName(DEFAULT_FLOOD_SCOPE_NAME);
if (r == NULL) {
r = region_map.putRegion(DEFAULT_FLOOD_SCOPE_NAME, 0); // auto-create the default scope region
if (r) { r->flags = 0; } // Allow-flood
}
if (r) {
region_map.setDefaultRegion(r);
region_map.getTransportKeysFor(*r, &default_scope, 1);
}
#endif
}
}
#if defined(WITH_BRIDGE) #if defined(WITH_BRIDGE)
if (_prefs.bridge_enabled) { if (_prefs.bridge_enabled) {
bridge.begin(); bridge.begin();
@@ -1119,6 +1156,17 @@ void MyMesh::begin(FILESYSTEM *fs, ArchiveStorage* archive) {
next_history_sample_ms = futureMillis(1000); next_history_sample_ms = futureMillis(1000);
} }
void MyMesh::sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis, uint8_t path_hash_size) {
if (scope.isNull()) {
sendFlood(pkt, delay_millis, path_hash_size);
} else {
uint16_t codes[2];
codes[0] = scope.calcTransportCode(pkt);
codes[1] = 0; // REVISIT: set to 'home' Region, for sender/return region?
sendFlood(pkt, codes, delay_millis, path_hash_size);
}
}
void MyMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) { void MyMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) {
set_radio_at = futureMillis(2000); // give CLI reply some time to be sent back, before applying temp radio params set_radio_at = futureMillis(2000); // give CLI reply some time to be sent back, before applying temp radio params
pending_freq = freq; pending_freq = freq;
@@ -1146,7 +1194,7 @@ void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
if (pkt) { if (pkt) {
if (flood) { if (flood) {
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); sendFloodScoped(default_scope, pkt, delay_millis, _prefs.path_hash_mode + 1);
} else { } else {
sendZeroHop(pkt, delay_millis); sendZeroHop(pkt, delay_millis);
} }
@@ -1257,6 +1305,25 @@ void MyMesh::formatStatsReply(char *reply, size_t reply_size) {
StatsFormatHelper::formatCoreStats(reply, reply_size, board, *_ms, _err_flags, _mgr); StatsFormatHelper::formatCoreStats(reply, reply_size, board, *_ms, _err_flags, _mgr);
} }
void MyMesh::startRegionsLoad() {
temp_map.resetFrom(region_map); // rebuild regions in a temp instance
memset(load_stack, 0, sizeof(load_stack));
load_stack[0] = &temp_map.getWildcard();
region_load_active = true;
}
bool MyMesh::saveRegions() {
return region_map.save(_fs);
}
void MyMesh::onDefaultRegionChanged(const RegionEntry* r) {
if (r) {
region_map.getTransportKeysFor(*r, &default_scope, 1);
} else {
memset(default_scope.key, 0, sizeof(default_scope.key));
}
}
void MyMesh::formatRadioStatsReply(char *reply, size_t reply_size) { void MyMesh::formatRadioStatsReply(char *reply, size_t reply_size) {
StatsFormatHelper::formatRadioStats(reply, reply_size, _radio, radio_driver, getTotalAirTime(), getReceiveAirTime()); StatsFormatHelper::formatRadioStats(reply, reply_size, _radio, radio_driver, getTotalAirTime(), getReceiveAirTime());
} }
@@ -1741,107 +1808,6 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
Serial.printf("\n"); Serial.printf("\n");
} }
reply[0] = 0; reply[0] = 0;
} else if (memcmp(command, "region", 6) == 0) {
reply[0] = 0;
const char* parts[4];
int n = mesh::Utils::parseTextParts(command, parts, 4, ' ');
if (n == 1) {
region_map.exportTo(reply, 160);
} else if (n >= 2 && strcmp(parts[1], "load") == 0) {
temp_map.resetFrom(region_map); // rebuild regions in a temp instance
memset(load_stack, 0, sizeof(load_stack));
load_stack[0] = &temp_map.getWildcard();
region_load_active = true;
} else if (n >= 2 && strcmp(parts[1], "save") == 0) {
_prefs.discovery_mod_timestamp = rtc_clock.getCurrentTime(); // this node is now 'modified' (for discovery info)
savePrefs();
bool success = region_map.save(_fs);
strcpy(reply, success ? "OK" : "Err - save failed");
} else if (n >= 3 && strcmp(parts[1], "allowf") == 0) {
auto region = region_map.findByNamePrefix(parts[2]);
if (region) {
region->flags &= ~REGION_DENY_FLOOD;
strcpy(reply, "OK");
} else {
strcpy(reply, "Err - unknown region");
}
} else if (n >= 3 && strcmp(parts[1], "denyf") == 0) {
auto region = region_map.findByNamePrefix(parts[2]);
if (region) {
region->flags |= REGION_DENY_FLOOD;
strcpy(reply, "OK");
} else {
strcpy(reply, "Err - unknown region");
}
} else if (n >= 3 && strcmp(parts[1], "get") == 0) {
auto region = region_map.findByNamePrefix(parts[2]);
if (region) {
auto parent = region_map.findById(region->parent);
if (parent && parent->id != 0) {
sprintf(reply, " %s (%s) %s", region->name, parent->name, (region->flags & REGION_DENY_FLOOD) ? "" : "F");
} else {
sprintf(reply, " %s %s", region->name, (region->flags & REGION_DENY_FLOOD) ? "" : "F");
}
} else {
strcpy(reply, "Err - unknown region");
}
} else if (n >= 3 && strcmp(parts[1], "home") == 0) {
auto home = region_map.findByNamePrefix(parts[2]);
if (home) {
region_map.setHomeRegion(home);
sprintf(reply, " home is now %s", home->name);
} else {
strcpy(reply, "Err - unknown region");
}
} else if (n == 2 && strcmp(parts[1], "home") == 0) {
auto home = region_map.getHomeRegion();
sprintf(reply, " home is %s", home ? home->name : "*");
} else if (n >= 3 && strcmp(parts[1], "put") == 0) {
auto parent = n >= 4 ? region_map.findByNamePrefix(parts[3]) : &region_map.getWildcard();
if (parent == NULL) {
strcpy(reply, "Err - unknown parent");
} else {
auto region = region_map.putRegion(parts[2], parent->id);
if (region == NULL) {
strcpy(reply, "Err - unable to put");
} else {
strcpy(reply, "OK");
}
}
} else if (n >= 3 && strcmp(parts[1], "remove") == 0) {
auto region = region_map.findByName(parts[2]);
if (region) {
if (region_map.removeRegion(*region)) {
strcpy(reply, "OK");
} else {
strcpy(reply, "Err - not empty");
}
} else {
strcpy(reply, "Err - not found");
}
} else if (n >= 3 && strcmp(parts[1], "list") == 0) {
uint8_t mask = 0;
bool invert = false;
if (strcmp(parts[2], "allowed") == 0) {
mask = REGION_DENY_FLOOD;
invert = false; // list regions that DON'T have DENY flag
} else if (strcmp(parts[2], "denied") == 0) {
mask = REGION_DENY_FLOOD;
invert = true; // list regions that DO have DENY flag
} else {
strcpy(reply, "Err - use 'allowed' or 'denied'");
return;
}
int len = region_map.exportNamesTo(reply, 160, mask, invert);
if (len == 0) {
strcpy(reply, "-none-");
}
} else {
strcpy(reply, "Err - ??");
}
} else if (memcmp(command, "discover.neighbors", 18) == 0) { } else if (memcmp(command, "discover.neighbors", 18) == 0) {
const char* sub = command + 18; const char* sub = command + 18;
while (*sub == ' ') sub++; while (*sub == ' ') sub++;
@@ -2391,7 +2357,7 @@ void MyMesh::loop() {
if (next_flood_advert && millisHasNowPassed(next_flood_advert)) { if (next_flood_advert && millisHasNowPassed(next_flood_advert)) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
uint32_t delay_millis = 0; uint32_t delay_millis = 0;
if (pkt) sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); if (pkt) sendFloodScoped(default_scope, pkt, delay_millis, _prefs.path_hash_mode + 1);
updateFloodAdvertTimer(); // schedule next flood advert updateFloodAdvertTimer(); // schedule next flood advert
updateAdvertTimer(); // also schedule local advert (so they don't overlap) updateAdvertTimer(); // also schedule local advert (so they don't overlap)
+10
查看文件
@@ -109,6 +109,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks, public WebPanelComm
RegionMap region_map, temp_map; RegionMap region_map, temp_map;
RegionEntry* load_stack[8]; RegionEntry* load_stack[8];
RegionEntry* recv_pkt_region; RegionEntry* recv_pkt_region;
TransportKey default_scope;
RateLimiter discover_limiter, anon_limiter; RateLimiter discover_limiter, anon_limiter;
uint32_t pending_discover_tag; uint32_t pending_discover_tag;
unsigned long pending_discover_until; unsigned long pending_discover_until;
@@ -211,6 +212,8 @@ protected:
bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override; bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;
void onControlDataRecv(mesh::Packet* packet) override; void onControlDataRecv(mesh::Packet* packet) override;
void sendFloodReply(mesh::Packet* packet, unsigned long delay_millis, uint8_t path_hash_size);
public: public:
MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables); MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables);
@@ -228,6 +231,9 @@ public:
_cli.savePrefs(_fs); _cli.savePrefs(_fs);
} }
void sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis, uint8_t path_hash_size);
// CommonCLICallbacks
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override; void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override;
bool formatFileSystem() override; bool formatFileSystem() override;
void sendSelfAdvertisement(int delay_millis, bool flood) override; void sendSelfAdvertisement(int delay_millis, bool flood) override;
@@ -248,11 +254,15 @@ public:
void formatRadioStatsReply(char *reply, size_t reply_size) override; void formatRadioStatsReply(char *reply, size_t reply_size) override;
void formatPacketStatsReply(char *reply, size_t reply_size) override; void formatPacketStatsReply(char *reply, size_t reply_size) override;
void formatMemoryReply(char *reply, size_t reply_size) override; void formatMemoryReply(char *reply, size_t reply_size) override;
void startRegionsLoad() override;
bool saveRegions() override;
void onDefaultRegionChanged(const RegionEntry* r) override;
mesh::LocalIdentity& getSelfId() override { return self_id; } mesh::LocalIdentity& getSelfId() override { return self_id; }
void saveIdentity(const mesh::LocalIdentity& new_id) override; void saveIdentity(const mesh::LocalIdentity& new_id) override;
void clearStats() override; void clearStats() override;
void handleCommand(uint32_t sender_timestamp, char* command, char* reply); void handleCommand(uint32_t sender_timestamp, char* command, char* reply);
void runWebCommand(const char* command, char* reply, size_t reply_size) override; void runWebCommand(const char* command, char* reply, size_t reply_size) override;
const char* getWebAdminPassword() const override { return _prefs.password; } const char* getWebAdminPassword() const override { return _prefs.password; }
+5 -1
查看文件
@@ -3,6 +3,10 @@
#include <WiFi.h> #include <WiFi.h>
#include <helpers/CommonCLI.h> #include <helpers/CommonCLI.h>
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
#define AUTO_OFF_MILLIS 20000 // 20 seconds #define AUTO_OFF_MILLIS 20000 // 20 seconds
#define BOOT_SCREEN_MILLIS 4000 // 4 seconds #define BOOT_SCREEN_MILLIS 4000 // 4 seconds
@@ -96,7 +100,7 @@ void UITask::loop() {
if (millis() >= _next_read) { if (millis() >= _next_read) {
int btnState = digitalRead(PIN_USER_BTN); int btnState = digitalRead(PIN_USER_BTN);
if (btnState != _prevBtnState) { if (btnState != _prevBtnState) {
if (btnState == LOW) { // pressed? if (btnState == USER_BTN_PRESSED) { // pressed?
if (_display->isOn()) { if (_display->isOn()) {
// TODO: any action ? // TODO: any action ?
} else { } else {
+131 -10
查看文件
@@ -75,7 +75,7 @@ void MyMesh::pushPostToClient(ClientInfo *client, PostInfo &post) {
if (reply) { if (reply) {
if (client->out_path_len == OUT_PATH_UNKNOWN) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
unsigned long delay_millis = 0; unsigned long delay_millis = 0;
sendFlood(reply, delay_millis, _prefs.path_hash_mode + 1); sendFloodScoped(default_scope, reply, delay_millis, _prefs.path_hash_mode + 1); // REVISIT
client->extra.room.ack_timeout = futureMillis(PUSH_ACK_TIMEOUT_FLOOD); client->extra.room.ack_timeout = futureMillis(PUSH_ACK_TIMEOUT_FLOOD);
} else { } else {
sendDirect(reply, client->out_path, client->out_path_len); sendDirect(reply, client->out_path, client->out_path_len);
@@ -286,6 +286,23 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
return true; return true;
} }
bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
// just try to determine region for packet (apply later in allowPacketForward())
if (pkt->getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD) {
recv_pkt_region = region_map.findMatch(pkt, REGION_DENY_FLOOD);
} else if (pkt->getRouteType() == ROUTE_TYPE_FLOOD) {
if (region_map.getWildcard().flags & REGION_DENY_FLOOD) {
recv_pkt_region = NULL;
} else {
recv_pkt_region = &region_map.getWildcard();
}
} else {
recv_pkt_region = NULL;
}
// do normal processing
return false;
}
void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const mesh::Identity &sender, void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const mesh::Identity &sender,
uint8_t *data, size_t len) { uint8_t *data, size_t len) {
if (packet->getPayloadType() == PAYLOAD_TYPE_ANON_REQ) { // received an initial request by a possible admin if (packet->getPayloadType() == PAYLOAD_TYPE_ANON_REQ) { // received an initial request by a possible admin
@@ -361,14 +378,14 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet *path = createPathReturn(sender, client->shared_secret, packet->path, packet->path_len, mesh::Packet *path = createPathReturn(sender, client->shared_secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, 13); PAYLOAD_TYPE_RESPONSE, reply_data, 13);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, client->shared_secret, reply_data, 13); mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, client->shared_secret, reply_data, 13);
if (reply) { if (reply) {
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); sendFloodReply(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -458,7 +475,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
if (send_ack) { if (send_ack) {
if (client->out_path_len == OUT_PATH_UNKNOWN) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
mesh::Packet *ack = createAck(ack_hash); mesh::Packet *ack = createAck(ack_hash);
if (ack) sendFlood(ack, TXT_ACK_DELAY, packet->getPathHashSize()); if (ack) sendFloodReply(ack, TXT_ACK_DELAY, packet->getPathHashSize());
delay_millis = TXT_ACK_DELAY + REPLY_DELAY_MILLIS; delay_millis = TXT_ACK_DELAY + REPLY_DELAY_MILLIS;
} else { } else {
uint32_t d = TXT_ACK_DELAY; uint32_t d = TXT_ACK_DELAY;
@@ -491,7 +508,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len); auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len);
if (reply) { if (reply) {
if (client->out_path_len == OUT_PATH_UNKNOWN) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(reply, delay_millis + SERVER_RESPONSE_DELAY, packet->getPathHashSize()); sendFloodReply(reply, delay_millis + SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
sendDirect(reply, client->out_path, client->out_path_len, delay_millis + SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, delay_millis + SERVER_RESPONSE_DELAY);
} }
@@ -546,14 +563,14 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len, mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len); mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len);
if (reply) { if (reply) {
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize()); sendFloodReply(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -595,12 +612,16 @@ void MyMesh::onAckRecv(mesh::Packet *packet, uint32_t ack_crc) {
MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondClock &ms, mesh::RNG &rng, MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondClock &ms, mesh::RNG &rng,
mesh::RTCClock &rtc, mesh::MeshTables &tables) mesh::RTCClock &rtc, mesh::MeshTables &tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables), : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
_cli(board, rtc, sensors, acl, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4) { region_map(key_store), temp_map(key_store),
_cli(board, rtc, sensors, region_map, acl, &_prefs, this),
telemetry(MAX_PACKET_PAYLOAD - 4)
{
last_millis = 0; last_millis = 0;
uptime_millis = 0; uptime_millis = 0;
next_local_advert = next_flood_advert = 0; next_local_advert = next_flood_advert = 0;
dirty_contacts_expiry = 0; dirty_contacts_expiry = 0;
_logging = false; _logging = false;
region_load_active = false;
set_radio_at = revert_radio_at = 0; set_radio_at = revert_radio_at = 0;
// defaults // defaults
@@ -638,6 +659,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
next_push = 0; next_push = 0;
memset(posts, 0, sizeof(posts)); memset(posts, 0, sizeof(posts));
_num_posted = _num_post_pushes = 0; _num_posted = _num_post_pushes = 0;
memset(default_scope.key, 0, sizeof(default_scope.key));
} }
void MyMesh::begin(FILESYSTEM *fs) { void MyMesh::begin(FILESYSTEM *fs) {
@@ -647,6 +670,27 @@ void MyMesh::begin(FILESYSTEM *fs) {
_cli.loadPrefs(_fs); _cli.loadPrefs(_fs);
acl.load(_fs, self_id); acl.load(_fs, self_id);
region_map.load(_fs);
// establish default-scope
{
RegionEntry* r = region_map.getDefaultRegion();
if (r) {
region_map.getTransportKeysFor(*r, &default_scope, 1);
} else {
#ifdef DEFAULT_FLOOD_SCOPE_NAME
r = region_map.findByName(DEFAULT_FLOOD_SCOPE_NAME);
if (r == NULL) {
r = region_map.putRegion(DEFAULT_FLOOD_SCOPE_NAME, 0); // auto-create the default scope region
if (r) { r->flags = 0; } // Allow-flood
}
if (r) {
region_map.setDefaultRegion(r);
region_map.getTransportKeysFor(*r, &default_scope, 1);
}
#endif
}
}
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
radio_set_tx_power(_prefs.tx_power_dbm); radio_set_tx_power(_prefs.tx_power_dbm);
@@ -662,6 +706,30 @@ void MyMesh::begin(FILESYSTEM *fs) {
#endif #endif
} }
void MyMesh::sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis, uint8_t path_hash_size) {
if (scope.isNull()) {
sendFlood(pkt, delay_millis, path_hash_size);
} else {
uint16_t codes[2];
codes[0] = scope.calcTransportCode(pkt);
codes[1] = 0; // REVISIT: set to 'home' Region, for sender/return region?
sendFlood(pkt, codes, delay_millis, path_hash_size);
}
}
void MyMesh::sendFloodReply(mesh::Packet* packet, unsigned long delay_millis, uint8_t path_hash_size) {
if (recv_pkt_region && !recv_pkt_region->isWildcard()) { // if _request_ packet scope is known, send reply with same scope
TransportKey scope;
if (region_map.getTransportKeysFor(*recv_pkt_region, &scope, 1) > 0) {
sendFloodScoped(scope, packet, delay_millis, path_hash_size);
} else {
sendFlood(packet, delay_millis, path_hash_size); // send un-scoped
}
} else {
sendFlood(packet, delay_millis, path_hash_size); // send un-scoped
}
}
void MyMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) { void MyMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) {
set_radio_at = futureMillis(2000); // give CLI reply some time to be sent back, before applying temp radio params set_radio_at = futureMillis(2000); // give CLI reply some time to be sent back, before applying temp radio params
pending_freq = freq; pending_freq = freq;
@@ -689,7 +757,7 @@ void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
if (pkt) { if (pkt) {
if (flood) { if (flood) {
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); sendFloodScoped(default_scope, pkt, delay_millis, _prefs.path_hash_mode + 1);
} else { } else {
sendZeroHop(pkt, delay_millis); sendZeroHop(pkt, delay_millis);
} }
@@ -746,6 +814,25 @@ void MyMesh::saveIdentity(const mesh::LocalIdentity &new_id) {
store.save("_main", new_id); store.save("_main", new_id);
} }
void MyMesh::startRegionsLoad() {
temp_map.resetFrom(region_map); // rebuild regions in a temp instance
memset(load_stack, 0, sizeof(load_stack));
load_stack[0] = &temp_map.getWildcard();
region_load_active = true;
}
bool MyMesh::saveRegions() {
return region_map.save(_fs);
}
void MyMesh::onDefaultRegionChanged(const RegionEntry* r) {
if (r) {
region_map.getTransportKeysFor(*r, &default_scope, 1);
} else {
memset(default_scope.key, 0, sizeof(default_scope.key));
}
}
void MyMesh::clearStats() { void MyMesh::clearStats() {
radio_driver.resetStats(); radio_driver.resetStats();
resetStats(); resetStats();
@@ -770,6 +857,40 @@ void MyMesh::formatMemoryReply(char *reply, size_t reply_size) {
} }
void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply) { void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply) {
if (region_load_active) {
if (StrHelper::isBlank(command)) { // empty/blank line, signal to terminate 'load' operation
region_map = temp_map; // copy over the temp instance as new current map
region_load_active = false;
sprintf(reply, "OK - loaded %d regions", region_map.getCount());
} else {
char *np = command;
while (*np == ' ') np++; // skip indent
int indent = np - command;
char *ep = np;
while (RegionMap::is_name_char(*ep)) ep++;
if (*ep) { *ep++ = 0; } // set null terminator for end of name
while (*ep && *ep != 'F') ep++; // look for (optional) flags
if (indent > 0 && indent < 8 && strlen(np) > 0) {
auto parent = load_stack[indent - 1];
if (parent) {
auto old = region_map.findByName(np);
auto nw = temp_map.putRegion(np, parent->id, old ? old->id : 0); // carry-over the current ID (if name already exists)
if (nw) {
nw->flags = old ? old->flags : (*ep == 'F' ? 0 : REGION_DENY_FLOOD); // carry-over flags from curr
load_stack[indent] = nw; // keep pointers to parent regions, to resolve parent_id's
}
}
}
reply[0] = 0;
}
return;
}
while (*command == ' ') while (*command == ' ')
command++; // skip leading spaces command++; // skip leading spaces
@@ -871,7 +992,7 @@ void MyMesh::loop() {
if (next_flood_advert && millisHasNowPassed(next_flood_advert)) { if (next_flood_advert && millisHasNowPassed(next_flood_advert)) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
uint32_t delay_millis = 0; uint32_t delay_millis = 0;
if (pkt) sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); if (pkt) sendFloodScoped(default_scope, pkt, delay_millis, _prefs.path_hash_mode + 1);
updateFloodAdvertTimer(); // schedule next flood advert updateFloodAdvertTimer(); // schedule next flood advert
updateAdvertTimer(); // also schedule local advert (so they don't overlap) updateAdvertTimer(); // also schedule local advert (so they don't overlap)
+17
查看文件
@@ -20,6 +20,7 @@
#include <helpers/CommonCLI.h> #include <helpers/CommonCLI.h>
#include <helpers/StatsFormatHelper.h> #include <helpers/StatsFormatHelper.h>
#include <helpers/ClientACL.h> #include <helpers/ClientACL.h>
#include <helpers/RegionMap.h>
#include <RTClib.h> #include <RTClib.h>
#include <target.h> #include <target.h>
@@ -93,7 +94,10 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
uint64_t uptime_millis; uint64_t uptime_millis;
unsigned long next_local_advert, next_flood_advert; unsigned long next_local_advert, next_flood_advert;
bool _logging; bool _logging;
bool region_load_active;
NodePrefs _prefs; NodePrefs _prefs;
TransportKeyStore key_store;
RegionMap region_map, temp_map;
ClientACL acl; ClientACL acl;
CommonCLI _cli; CommonCLI _cli;
unsigned long dirty_contacts_expiry; unsigned long dirty_contacts_expiry;
@@ -104,6 +108,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
int next_post_idx; int next_post_idx;
PostInfo posts[MAX_UNSYNCED_POSTS]; // cyclic queue PostInfo posts[MAX_UNSYNCED_POSTS]; // cyclic queue
CayenneLPP telemetry; CayenneLPP telemetry;
RegionEntry* load_stack[8];
RegionEntry* recv_pkt_region;
TransportKey default_scope;
unsigned long set_radio_at, revert_radio_at; unsigned long set_radio_at, revert_radio_at;
float pending_freq; float pending_freq;
float pending_bw; float pending_bw;
@@ -144,6 +151,8 @@ protected:
return _prefs.multi_acks; return _prefs.multi_acks;
} }
bool filterRecvFloodPacket(mesh::Packet* pkt) override;
bool allowPacketForward(const mesh::Packet* packet) override; bool allowPacketForward(const mesh::Packet* packet) override;
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override; void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override;
int searchPeersByHash(const uint8_t* hash) override ; int searchPeersByHash(const uint8_t* hash) override ;
@@ -158,6 +167,8 @@ protected:
} }
#endif #endif
void sendFloodReply(mesh::Packet* packet, unsigned long delay_millis, uint8_t path_hash_size);
public: public:
MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables); MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables);
@@ -175,6 +186,9 @@ public:
_cli.savePrefs(_fs); _cli.savePrefs(_fs);
} }
void sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis, uint8_t path_hash_size);
// CommonCLICallbacks
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override; void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override;
bool formatFileSystem() override; bool formatFileSystem() override;
void sendSelfAdvertisement(int delay_millis, bool flood) override; void sendSelfAdvertisement(int delay_millis, bool flood) override;
@@ -197,6 +211,9 @@ public:
void formatRadioStatsReply(char *reply, size_t reply_size) override; void formatRadioStatsReply(char *reply, size_t reply_size) override;
void formatPacketStatsReply(char *reply, size_t reply_size) override; void formatPacketStatsReply(char *reply, size_t reply_size) override;
void formatMemoryReply(char *reply, size_t reply_size) override; void formatMemoryReply(char *reply, size_t reply_size) override;
void startRegionsLoad() override;
bool saveRegions() override;
void onDefaultRegionChanged(const RegionEntry* r) override;
mesh::LocalIdentity& getSelfId() override { return self_id; } mesh::LocalIdentity& getSelfId() override { return self_id; }
+5 -1
查看文件
@@ -2,6 +2,10 @@
#include <Arduino.h> #include <Arduino.h>
#include <helpers/CommonCLI.h> #include <helpers/CommonCLI.h>
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
#define AUTO_OFF_MILLIS 20000 // 20 seconds #define AUTO_OFF_MILLIS 20000 // 20 seconds
#define BOOT_SCREEN_MILLIS 4000 // 4 seconds #define BOOT_SCREEN_MILLIS 4000 // 4 seconds
@@ -85,7 +89,7 @@ void UITask::loop() {
if (millis() >= _next_read) { if (millis() >= _next_read) {
int btnState = digitalRead(PIN_USER_BTN); int btnState = digitalRead(PIN_USER_BTN);
if (btnState != _prevBtnState) { if (btnState != _prevBtnState) {
if (btnState == LOW) { // pressed? if (btnState == USER_BTN_PRESSED) { // pressed?
if (_display->isOn()) { if (_display->isOn()) {
// TODO: any action ? // TODO: any action ?
} else { } else {
+25 -1
查看文件
@@ -696,7 +696,9 @@ void SensorMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables) SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables), : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
_cli(board, rtc, sensors, acl, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4) region_map(key_store),
_cli(board, rtc, sensors, region_map, acl, &_prefs, this),
telemetry(MAX_PACKET_PAYLOAD - 4)
{ {
next_local_advert = next_flood_advert = 0; next_local_advert = next_flood_advert = 0;
dirty_contacts_expiry = 0; dirty_contacts_expiry = 0;
@@ -730,6 +732,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
_prefs.gps_interval = 0; _prefs.gps_interval = 0;
_prefs.advert_loc_policy = ADVERT_LOC_PREFS; _prefs.advert_loc_policy = ADVERT_LOC_PREFS;
_prefs.battery_reporting_enabled = 1; _prefs.battery_reporting_enabled = 1;
memset(default_scope.key, 0, sizeof(default_scope.key));
} }
void SensorMesh::begin(FILESYSTEM* fs) { void SensorMesh::begin(FILESYSTEM* fs) {
@@ -739,6 +742,27 @@ void SensorMesh::begin(FILESYSTEM* fs) {
_cli.loadPrefs(_fs); _cli.loadPrefs(_fs);
acl.load(_fs, self_id); acl.load(_fs, self_id);
region_map.load(_fs);
// establish default-scope
{
RegionEntry* r = region_map.getDefaultRegion();
if (r) {
region_map.getTransportKeysFor(*r, &default_scope, 1);
} else {
#ifdef DEFAULT_FLOOD_SCOPE_NAME
r = region_map.findByName(DEFAULT_FLOOD_SCOPE_NAME);
if (r == NULL) {
r = region_map.putRegion(DEFAULT_FLOOD_SCOPE_NAME, 0); // auto-create the default scope region
if (r) { r->flags = 0; } // Allow-flood
}
if (r) {
region_map.setDefaultRegion(r);
region_map.getTransportKeysFor(*r, &default_scope, 1);
}
#endif
}
}
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
radio_set_tx_power(_prefs.tx_power_dbm); radio_set_tx_power(_prefs.tx_power_dbm);
+4
查看文件
@@ -22,6 +22,7 @@
#include <helpers/CommonCLI.h> #include <helpers/CommonCLI.h>
#include <helpers/StatsFormatHelper.h> #include <helpers/StatsFormatHelper.h>
#include <helpers/ClientACL.h> #include <helpers/ClientACL.h>
#include <helpers/RegionMap.h>
#include <RTClib.h> #include <RTClib.h>
#include <target.h> #include <target.h>
@@ -139,6 +140,9 @@ private:
uint8_t reply_data[MAX_PACKET_PAYLOAD]; uint8_t reply_data[MAX_PACKET_PAYLOAD];
unsigned long dirty_contacts_expiry; unsigned long dirty_contacts_expiry;
CayenneLPP telemetry; CayenneLPP telemetry;
TransportKeyStore key_store;
RegionMap region_map;
TransportKey default_scope;
uint32_t last_read_time; uint32_t last_read_time;
int matching_peer_indexes[MAX_SEARCH_RESULTS]; int matching_peer_indexes[MAX_SEARCH_RESULTS];
int num_alert_tasks; int num_alert_tasks;
+5 -1
查看文件
@@ -2,6 +2,10 @@
#include <Arduino.h> #include <Arduino.h>
#include <helpers/CommonCLI.h> #include <helpers/CommonCLI.h>
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
#define AUTO_OFF_MILLIS 20000 // 20 seconds #define AUTO_OFF_MILLIS 20000 // 20 seconds
#define BOOT_SCREEN_MILLIS 4000 // 4 seconds #define BOOT_SCREEN_MILLIS 4000 // 4 seconds
@@ -85,7 +89,7 @@ void UITask::loop() {
if (millis() >= _next_read) { if (millis() >= _next_read) {
int btnState = digitalRead(PIN_USER_BTN); int btnState = digitalRead(PIN_USER_BTN);
if (btnState != _prevBtnState) { if (btnState != _prevBtnState) {
if (btnState == LOW) { // pressed? if (btnState == USER_BTN_PRESSED) { // pressed?
if (_display->isOn()) { if (_display->isOn()) {
// TODO: any action ? // TODO: any action ?
} else { } else {
檔案差異因為檔案過大而無法顯示 載入差異
+19 -3
查看文件
@@ -4,6 +4,7 @@
#include <helpers/IdentityStore.h> #include <helpers/IdentityStore.h>
#include <helpers/SensorManager.h> #include <helpers/SensorManager.h>
#include <helpers/ClientACL.h> #include <helpers/ClientACL.h>
#include <helpers/RegionMap.h>
#if defined(WITH_RS232_BRIDGE) || defined(WITH_ESPNOW_BRIDGE) #if defined(WITH_RS232_BRIDGE) || defined(WITH_ESPNOW_BRIDGE)
#define WITH_BRIDGE #define WITH_BRIDGE
@@ -90,6 +91,16 @@ public:
virtual void clearStats() = 0; virtual void clearStats() = 0;
virtual void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) = 0; virtual void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) = 0;
virtual void startRegionsLoad() {
// no op by default
}
virtual bool saveRegions() {
return false;
}
virtual void onDefaultRegionChanged(const RegionEntry* r) {
// no op by default
}
virtual void setBridgeState(bool enable) { virtual void setBridgeState(bool enable) {
// no op by default // no op by default
}; };
@@ -109,6 +120,7 @@ class CommonCLI {
CommonCLICallbacks* _callbacks; CommonCLICallbacks* _callbacks;
mesh::MainBoard* _board; mesh::MainBoard* _board;
SensorManager* _sensors; SensorManager* _sensors;
RegionMap* _region_map;
ClientACL* _acl; ClientACL* _acl;
char tmp[PRV_KEY_SIZE*2 + 4]; char tmp[PRV_KEY_SIZE*2 + 4];
@@ -116,12 +128,16 @@ class CommonCLI {
void savePrefs(); void savePrefs();
void loadPrefsInt(FILESYSTEM* _fs, const char* filename); void loadPrefsInt(FILESYSTEM* _fs, const char* filename);
void handleRegionCmd(char* command, char* reply);
void handleGetCmd(uint32_t sender_timestamp, char* command, char* reply);
void handleSetCmd(uint32_t sender_timestamp, char* command, char* reply);
public: public:
CommonCLI(mesh::MainBoard& board, mesh::RTCClock& rtc, SensorManager& sensors, ClientACL& acl, NodePrefs* prefs, CommonCLICallbacks* callbacks) CommonCLI(mesh::MainBoard& board, mesh::RTCClock& rtc, SensorManager& sensors, RegionMap& region_map, ClientACL& acl, NodePrefs* prefs, CommonCLICallbacks* callbacks)
: _board(&board), _rtc(&rtc), _sensors(&sensors), _acl(&acl), _prefs(prefs), _callbacks(callbacks) { } : _board(&board), _rtc(&rtc), _sensors(&sensors), _region_map(&region_map), _acl(&acl), _prefs(prefs), _callbacks(callbacks) { }
void loadPrefs(FILESYSTEM* _fs); void loadPrefs(FILESYSTEM* _fs);
void savePrefs(FILESYSTEM* _fs); void savePrefs(FILESYSTEM* _fs);
void handleCommand(uint32_t sender_timestamp, const char* command, char* reply); void handleCommand(uint32_t sender_timestamp, char* command, char* reply);
uint8_t buildAdvertData(uint8_t node_type, uint8_t* app_data); uint8_t buildAdvertData(uint8_t node_type, uint8_t* app_data);
}; };
+4
查看文件
@@ -3,6 +3,10 @@
#include <MeshCore.h> #include <MeshCore.h>
#include <Arduino.h> #include <Arduino.h>
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
#if defined(ESP_PLATFORM) #if defined(ESP_PLATFORM)
#include <rom/rtc.h> #include <rom/rtc.h>
+34 -17
查看文件
@@ -42,7 +42,8 @@ private:
RegionMap::RegionMap(TransportKeyStore& store) : _store(&store) { RegionMap::RegionMap(TransportKeyStore& store) : _store(&store) {
next_id = 1; num_regions = 0; home_id = 0; next_id = 1; num_regions = 0;
default_id = home_id = 0;
wildcard.id = wildcard.parent = 0; wildcard.id = wildcard.parent = 0;
wildcard.flags = 0; // default behaviour, allow flood and direct wildcard.flags = 0; // default behaviour, allow flood and direct
strcpy(wildcard.name, "*"); strcpy(wildcard.name, "*");
@@ -79,9 +80,11 @@ bool RegionMap::load(FILESYSTEM* _fs, const char* path) {
if (file) { if (file) {
uint8_t pad[128]; uint8_t pad[128];
num_regions = 0; next_id = 1; home_id = 0; num_regions = 0; next_id = 1;
default_id = home_id = 0;
bool success = file.read(pad, 5) == 5; // reserved header bool success = file.read(pad, 3) == 3; // reserved header
success = success && file.read((uint8_t *) &default_id, sizeof(default_id)) == sizeof(default_id);
success = success && file.read((uint8_t *) &home_id, sizeof(home_id)) == sizeof(home_id); success = success && file.read((uint8_t *) &home_id, sizeof(home_id)) == sizeof(home_id);
success = success && file.read((uint8_t *) &wildcard.flags, sizeof(wildcard.flags)) == sizeof(wildcard.flags); success = success && file.read((uint8_t *) &wildcard.flags, sizeof(wildcard.flags)) == sizeof(wildcard.flags);
success = success && file.read((uint8_t *) &next_id, sizeof(next_id)) == sizeof(next_id); success = success && file.read((uint8_t *) &next_id, sizeof(next_id)) == sizeof(next_id);
@@ -117,7 +120,8 @@ bool RegionMap::save(FILESYSTEM* _fs, const char* path) {
uint8_t pad[128]; uint8_t pad[128];
memset(pad, 0, sizeof(pad)); memset(pad, 0, sizeof(pad));
bool success = file.write(pad, 5) == 5; // reserved header bool success = file.write(pad, 3) == 3; // reserved header
success = success && file.write((uint8_t *) &default_id, sizeof(default_id)) == sizeof(default_id);
success = success && file.write((uint8_t *) &home_id, sizeof(home_id)) == sizeof(home_id); success = success && file.write((uint8_t *) &home_id, sizeof(home_id)) == sizeof(home_id);
success = success && file.write((uint8_t *) &wildcard.flags, sizeof(wildcard.flags)) == sizeof(wildcard.flags); success = success && file.write((uint8_t *) &wildcard.flags, sizeof(wildcard.flags)) == sizeof(wildcard.flags);
success = success && file.write((uint8_t *) &next_id, sizeof(next_id)) == sizeof(next_id); success = success && file.write((uint8_t *) &next_id, sizeof(next_id)) == sizeof(next_id);
@@ -164,24 +168,29 @@ RegionEntry* RegionMap::putRegion(const char* name, uint16_t parent_id, uint16_t
return region; return region;
} }
int RegionMap::getTransportKeysFor(const RegionEntry& src, TransportKey dest[], int max_num) {
int num;
if (src.name[0] == '$') { // private region
num = _store->loadKeysFor(src.id, dest, max_num);
} else if (src.name[0] == '#') { // auto hashtag region
_store->getAutoKeyFor(src.id, src.name, dest[0]);
num = 1;
} else { // new: implicit auto hashtag region
char tmp[sizeof(src.name)];
tmp[0] = '#';
strcpy(&tmp[1], src.name);
_store->getAutoKeyFor(src.id, tmp, dest[0]);
num = 1;
}
return num;
}
RegionEntry* RegionMap::findMatch(mesh::Packet* packet, uint8_t mask) { RegionEntry* RegionMap::findMatch(mesh::Packet* packet, uint8_t mask) {
for (int i = 0; i < num_regions; i++) { for (int i = 0; i < num_regions; i++) {
auto region = &regions[i]; auto region = &regions[i];
if ((region->flags & mask) == 0) { // does region allow this? (per 'mask' param) if ((region->flags & mask) == 0) { // does region allow this? (per 'mask' param)
TransportKey keys[4]; TransportKey keys[4];
int num; int num = getTransportKeysFor(*region, keys, 4);
if (region->name[0] == '$') { // private region
num = _store->loadKeysFor(region->id, keys, 4);
} else if (region->name[0] == '#') { // auto hashtag region
_store->getAutoKeyFor(region->id, region->name, keys[0]);
num = 1;
} else { // new: implicit auto hashtag region
char tmp[sizeof(region->name)];
tmp[0] = '#';
strcpy(&tmp[1], region->name);
_store->getAutoKeyFor(region->id, tmp, keys[0]);
num = 1;
}
for (int j = 0; j < num; j++) { for (int j = 0; j < num; j++) {
uint16_t code = keys[j].calcTransportCode(packet); uint16_t code = keys[j].calcTransportCode(packet);
if (packet->transport_codes[0] == code) { // a match!! if (packet->transport_codes[0] == code) { // a match!!
@@ -237,6 +246,14 @@ void RegionMap::setHomeRegion(const RegionEntry* home) {
home_id = home ? home->id : 0; home_id = home ? home->id : 0;
} }
RegionEntry* RegionMap::getDefaultRegion() {
return default_id == 0 ? NULL : findById(default_id);
}
void RegionMap::setDefaultRegion(const RegionEntry* def) {
default_id = def ? def->id : 0;
}
bool RegionMap::removeRegion(const RegionEntry& region) { bool RegionMap::removeRegion(const RegionEntry& region) {
if (region.id == 0) return false; // failed (cannot remove the wildcard Region) if (region.id == 0) return false; // failed (cannot remove the wildcard Region)
+6 -1
查看文件
@@ -16,11 +16,13 @@ struct RegionEntry {
uint16_t parent; uint16_t parent;
uint8_t flags; uint8_t flags;
char name[31]; char name[31];
bool isWildcard() const { return id == 0; }
}; };
class RegionMap { class RegionMap {
TransportKeyStore* _store; TransportKeyStore* _store;
uint16_t next_id, home_id; uint16_t next_id, home_id, default_id;
uint16_t num_regions; uint16_t num_regions;
RegionEntry regions[MAX_REGION_ENTRIES]; RegionEntry regions[MAX_REGION_ENTRIES];
RegionEntry wildcard; RegionEntry wildcard;
@@ -43,6 +45,8 @@ public:
RegionEntry* findById(uint16_t id); RegionEntry* findById(uint16_t id);
RegionEntry* getHomeRegion(); // NOTE: can be NULL RegionEntry* getHomeRegion(); // NOTE: can be NULL
void setHomeRegion(const RegionEntry* home); void setHomeRegion(const RegionEntry* home);
RegionEntry* getDefaultRegion(); // NOTE: can be NULL
void setDefaultRegion(const RegionEntry* def);
bool removeRegion(const RegionEntry& region); bool removeRegion(const RegionEntry& region);
bool clear(); bool clear();
void resetFrom(const RegionMap& src) { num_regions = 0; next_id = src.next_id; } void resetFrom(const RegionMap& src) { num_regions = 0; next_id = src.next_id; }
@@ -50,6 +54,7 @@ public:
const RegionEntry* getByIdx(int i) const { return &regions[i]; } const RegionEntry* getByIdx(int i) const { return &regions[i]; }
const RegionEntry* getRoot() const { return &wildcard; } const RegionEntry* getRoot() const { return &wildcard; }
int exportNamesTo(char *dest, int max_len, uint8_t mask, bool invert = false); int exportNamesTo(char *dest, int max_len, uint8_t mask, bool invert = false);
int getTransportKeysFor(const RegionEntry& src, TransportKey dest[], int max_num);
void exportTo(Stream& out) const; void exportTo(Stream& out) const;
size_t exportTo(char *dest, size_t max_len) const; size_t exportTo(char *dest, size_t max_len) const;
+6
查看文件
@@ -62,9 +62,15 @@ LPS22HBClass LPS22HB(*TELEM_WIRE);
#endif #endif
#if ENV_INCLUDE_INA3221 #if ENV_INCLUDE_INA3221
#ifndef TELEM_INA3221_ADDRESS
#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address
#endif
#ifndef TELEM_INA3221_SHUNT_VALUE
#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts #define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts
#endif
#ifndef TELEM_INA3221_NUM_CHANNELS
#define TELEM_INA3221_NUM_CHANNELS 3 #define TELEM_INA3221_NUM_CHANNELS 3
#endif
#include <Adafruit_INA3221.h> #include <Adafruit_INA3221.h>
static Adafruit_INA3221 INA3221; static Adafruit_INA3221 INA3221;
#endif #endif
+1 -1
查看文件
@@ -178,7 +178,7 @@ build_flags =
${Heltec_lora32_v2.build_flags} ${Heltec_lora32_v2.build_flags}
-I examples/companion_radio/ui-new -I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SSD1306Display -D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=160 -D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8 -D MAX_GROUP_CHANNELS=8
-D WIFI_DEBUG_LOGGING=1 -D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"' -D WIFI_SSID='"myssid"'
+4 -1
查看文件
@@ -11,6 +11,9 @@
#ifndef PIN_ADC_CTRL // set in platformio.ini for Heltec Wireless Tracker (2) #ifndef PIN_ADC_CTRL // set in platformio.ini for Heltec Wireless Tracker (2)
#define PIN_ADC_CTRL 37 #define PIN_ADC_CTRL 37
#endif #endif
#ifndef ADC_MULTIPLIER //default ADC multiplier
#define ADC_MULTIPLIER 5.42
#endif
#define PIN_ADC_CTRL_ACTIVE LOW #define PIN_ADC_CTRL_ACTIVE LOW
#define PIN_ADC_CTRL_INACTIVE HIGH #define PIN_ADC_CTRL_INACTIVE HIGH
@@ -95,7 +98,7 @@ public:
digitalWrite(PIN_ADC_CTRL, !adc_active_state); digitalWrite(PIN_ADC_CTRL, !adc_active_state);
uint16_t mv = (5.42 * (3.3 / 1024.0) * raw) * 1000; uint16_t mv = (ADC_MULTIPLIER * (3.3 / 1024.0) * raw) * 1000;
// Heltec V3 USB-powered boards without a battery can bias or float the // Heltec V3 USB-powered boards without a battery can bias or float the
// VBAT sense rail, which shows up as an impossible LiPo voltage. // VBAT sense rail, which shows up as an impossible LiPo voltage.
+2
查看文件
@@ -207,6 +207,7 @@ build_flags =
-I examples/companion_radio/ui-new -I examples/companion_radio/ui-new
-D MAX_CONTACTS=350 -D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40 -D MAX_GROUP_CHANNELS=40
-D OFFLINE_QUEUE_SIZE=256
-D DISPLAY_CLASS=SSD1306Display -D DISPLAY_CLASS=SSD1306Display
-D WIFI_DEBUG_LOGGING=1 -D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"' -D WIFI_SSID='"myssid"'
@@ -370,6 +371,7 @@ build_flags =
-I examples/companion_radio/ui-new -I examples/companion_radio/ui-new
-D MAX_CONTACTS=350 -D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40 -D MAX_GROUP_CHANNELS=40
-D OFFLINE_QUEUE_SIZE=256
-D DISPLAY_CLASS=ST7789LCDDisplay -D DISPLAY_CLASS=ST7789LCDDisplay
-D WIFI_DEBUG_LOGGING=1 -D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"' -D WIFI_SSID='"myssid"'
+1
查看文件
@@ -22,6 +22,7 @@ build_flags =
;-D PIN_BOARD_SCL=18 ; same GPIO as P_LORA_TX_LED ;-D PIN_BOARD_SCL=18 ; same GPIO as P_LORA_TX_LED
-D PIN_USER_BTN=0 -D PIN_USER_BTN=0
-D PIN_VEXT_EN=45 -D PIN_VEXT_EN=45
-D ADC_MULTIPLIER=8.4
-D PIN_VBAT_READ=20 -D PIN_VBAT_READ=20
-D PIN_ADC_CTRL=19 -D PIN_ADC_CTRL=19
-D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO2_AS_RF_SWITCH=true
+1
查看文件
@@ -154,6 +154,7 @@ build_flags =
-I examples/companion_radio/ui-new -I examples/companion_radio/ui-new
-D MAX_CONTACTS=350 -D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40 -D MAX_GROUP_CHANNELS=40
-D OFFLINE_QUEUE_SIZE=256
-D WIFI_DEBUG_LOGGING=1 -D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"' -D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"' -D WIFI_PWD='"mypwd"'
+1 -1
查看文件
@@ -131,7 +131,7 @@ extends = LilyGo_TLora_V2_1_1_6
build_flags = build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags} ${LilyGo_TLora_V2_1_1_6.build_flags}
-I examples/companion_radio/ui-new -I examples/companion_radio/ui-new
-D MAX_CONTACTS=160 -D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8 -D MAX_GROUP_CHANNELS=8
-D WIFI_SSID='"ssid"' -D WIFI_SSID='"ssid"'
-D WIFI_PWD='"password"' -D WIFI_PWD='"password"'
+1 -1
查看文件
@@ -63,7 +63,7 @@ public:
digitalWrite(LED_PIN, LOW); digitalWrite(LED_PIN, LOW);
#endif #endif
#ifdef BUTTON_PIN #ifdef BUTTON_PIN
nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_HIGH); nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
#endif #endif
sd_power_system_off(); sd_power_system_off();
} }
-1
查看文件
@@ -21,7 +21,6 @@ build_flags = ${nrf52840_me25ls01.build_flags}
-I variants/minewsemi_me25ls01 -I variants/minewsemi_me25ls01
-D me25ls01 -D me25ls01
-D PIN_USER_BTN=27 -D PIN_USER_BTN=27
-D USER_BTN_PRESSED=HIGH
-D PIN_STATUS_LED=39 -D PIN_STATUS_LED=39
-D P_LORA_TX_LED=22 -D P_LORA_TX_LED=22
-D RADIO_CLASS=CustomLR1110 -D RADIO_CLASS=CustomLR1110
+1 -1
查看文件
@@ -43,7 +43,7 @@ public:
uint8_t v = digitalRead(BUTTON_PIN); uint8_t v = digitalRead(BUTTON_PIN);
if (v != btn_prev_state) { if (v != btn_prev_state) {
btn_prev_state = v; btn_prev_state = v;
return (v == LOW) ? 1 : -1; return (v == USER_BTN_PRESSED) ? 1 : -1;
} }
#endif #endif
return 0; return 0;
+1 -1
查看文件
@@ -22,7 +22,7 @@ build_flags = ${nrf52_base.build_flags}
-D P_LORA_NSS=12 ; P0.12 -D P_LORA_NSS=12 ; P0.12
-D P_LORA_DIO_1=33 ; P1.1 -D P_LORA_DIO_1=33 ; P1.1
-D P_LORA_MISO=40 ; P1.8 -D P_LORA_MISO=40 ; P1.8
-D P_LORA_MOSI=41 ; P0.9 -D P_LORA_MOSI=41 ; P1.9
-D P_LORA_RESET=42 ; P1.10 -D P_LORA_RESET=42 ; P1.10
-D LR11X0_DIO_AS_RF_SWITCH=true -D LR11X0_DIO_AS_RF_SWITCH=true
-D LR11X0_DIO3_TCXO_VOLTAGE=1.6 -D LR11X0_DIO3_TCXO_VOLTAGE=1.6
+1 -1
查看文件
@@ -55,7 +55,7 @@ const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] =
42, // P1.10, LORA_RESET 42, // P1.10, LORA_RESET
43, // P1.11, GPS_EN 43, // P1.11, GPS_EN
44, // P1.12, GPS_SLEEP_INT 44, // P1.12, GPS_SLEEP_INT
45, // P1.13 45, // P1.13, FLASH_ENABLE
46, // P1.14, GPS_RESETB 46, // P1.14, GPS_RESETB
47, // P1.15, PIN_GPS_RESET 47, // P1.15, PIN_GPS_RESET
255, // NRFX_SPIM_PIN_NOT_USED 255, // NRFX_SPIM_PIN_NOT_USED
+2 -2
查看文件
@@ -97,7 +97,7 @@
#define LORA_BUSY (7) // P0.7 #define LORA_BUSY (7) // P0.7
#define LORA_SCLK (PIN_SPI_SCK) // P0.11 #define LORA_SCLK (PIN_SPI_SCK) // P0.11
#define LORA_MISO (PIN_SPI_MISO) // P1.8 #define LORA_MISO (PIN_SPI_MISO) // P1.8
#define LORA_MOSI (PIN_SPI_MOSI) // P0.9 #define LORA_MOSI (PIN_SPI_MOSI) // P1.9
#define LR11X0_DIO_AS_RF_SWITCH true #define LR11X0_DIO_AS_RF_SWITCH true
#define LR11X0_DIO3_TCXO_VOLTAGE 1.6 #define LR11X0_DIO3_TCXO_VOLTAGE 1.6
@@ -133,4 +133,4 @@
// Buzzer // Buzzer
#define BUZZER_EN (37) // P1.5 #define BUZZER_EN (37) // P1.5
#define BUZZER_PIN (25) // P0.25 #define BUZZER_PIN (25) // P0.25
-1
查看文件
@@ -10,7 +10,6 @@ build_flags = ${nrf52_base.build_flags}
-I src/helpers/ui -I src/helpers/ui
-D THINKNODE_M3 -D THINKNODE_M3
-D PIN_USER_BTN=12 -D PIN_USER_BTN=12
-D USER_BTN_PRESSED=LOW
-D PIN_STATUS_LED=35 -D PIN_STATUS_LED=35
-D RADIO_CLASS=CustomLR1110 -D RADIO_CLASS=CustomLR1110
-D WRAPPER_CLASS=CustomLR1110Wrapper -D WRAPPER_CLASS=CustomLR1110Wrapper
+2 -1
查看文件
@@ -20,7 +20,8 @@ build_flags = ${rp2040_base.build_flags}
-D P_LORA_MOSI=15 -D P_LORA_MOSI=15
-D P_LORA_TX_LED=25 -D P_LORA_TX_LED=25
-D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=0 -D SX126X_RXEN=17
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_RX_BOOSTED_GAIN=1 -D SX126X_RX_BOOSTED_GAIN=1
-D LORA_TX_POWER=22 -D LORA_TX_POWER=22
; Debug options ; Debug options
-1
查看文件
@@ -9,7 +9,6 @@ build_flags = ${stm32_base.build_flags}
-D RX_BOOSTED_GAIN=true -D RX_BOOSTED_GAIN=true
-D P_LORA_TX_LED=LED_RED -D P_LORA_TX_LED=LED_RED
-D PIN_USER_BTN=USER_BTN -D PIN_USER_BTN=USER_BTN
-D USER_BTN_PRESSED=LOW
-I variants/wio-e5-mini -I variants/wio-e5-mini
build_src_filter = ${stm32_base.build_src_filter} build_src_filter = ${stm32_base.build_src_filter}
+<../variants/wio-e5-mini> +<../variants/wio-e5-mini>
+5 -1
查看文件
@@ -4,6 +4,10 @@
#include <Arduino.h> #include <Arduino.h>
#include <helpers/NRF52Board.h> #include <helpers/NRF52Board.h>
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
#ifdef XIAO_NRF52 #ifdef XIAO_NRF52
class XiaoNrf52Board : public NRF52BoardDCDC { class XiaoNrf52Board : public NRF52BoardDCDC {
@@ -35,7 +39,7 @@ public:
// set led on and wait for button release before poweroff // set led on and wait for button release before poweroff
digitalWrite(PIN_LED, LOW); digitalWrite(PIN_LED, LOW);
#ifdef PIN_USER_BTN #ifdef PIN_USER_BTN
while(digitalRead(PIN_USER_BTN) == LOW); while(digitalRead(PIN_USER_BTN) == USER_BTN_PRESSED);
#endif #endif
digitalWrite(LED_GREEN, HIGH); digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_BLUE, HIGH); digitalWrite(LED_BLUE, HIGH);
+2 -2
查看文件
@@ -72,11 +72,11 @@ build_flags =
-I examples/companion_radio/ui-orig -I examples/companion_radio/ui-orig
-D MAX_CONTACTS=350 -D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40 -D MAX_GROUP_CHANNELS=40
-D OFFLINE_QUEUE_SIZE=256
-D QSPIFLASH=1 -D QSPIFLASH=1
; -D MESH_PACKET_LOGGING=1 ; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1 ; -D MESH_DEBUG=1
build_src_filter = ${Xiao_nrf52.build_src_filter} build_src_filter = ${Xiao_nrf52.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio/*.cpp> +<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp> +<../examples/companion_radio/ui-orig/*.cpp>
lib_deps = lib_deps =
@@ -117,4 +117,4 @@ build_flags =
build_src_filter = ${Xiao_nrf52.build_src_filter} build_src_filter = ${Xiao_nrf52.build_src_filter}
+<../examples/kiss_modem/*.cpp> +<../examples/kiss_modem/*.cpp>
lib_deps = lib_deps =
${Xiao_nrf52.lib_deps} ${Xiao_nrf52.lib_deps}