Compare commits

..

12 Commits

Author SHA1 Message Date
Matthias Wientapper
14c00ace72 Integration of upstrem PR #1297 2026-01-14 11:09:17 +01:00
Matthias Wientapper
e81ce6158e Integration of upstrem PR #1199 2026-01-14 11:07:25 +01:00
Matthias Wientapper
c9d6927d26 Add cli config flood.advert.base
0 = forwarding flood adverts off
1 = forwarding flood adverts on (unrestricted)
0.308 (default) = prob. forwarding according to #1338
2026-01-14 10:53:09 +01:00
Matthias Wientapper
0b947f9d1b Limit flood advert packet forwarding for roomservers as well 2026-01-14 10:51:04 +01:00
Matthias Wientapper
1798e44f01 Limit flood advert packet forwarding, implements #1223 2026-01-14 10:51:04 +01:00
João Brázio
e563529cc5 Refactor default advert intervals to use defined constants 2025-12-15 16:19:05 +00:00
João Brázio
09a20d72e7 Implements preprocessor flags to control advert limits
https://github.com/meshcore-dev/MeshCore/pull/1217#issuecomment-3654930555
2025-12-15 12:17:20 +00:00
João Brázio
14f00fe688 Update advertisement condition to include NO_BOOT_ADVERT check 2025-12-14 01:12:38 +00:00
João Brázio
ce3b6e67f9 Merge remote-tracking branch 'upstream/dev' into jbrazio/2025_7a6560a0 2025-12-14 01:12:20 +00:00
João Brázio
3a497a4b99 Fix control data reception handling in STEALTH_MODE 2025-12-10 10:37:10 +00:00
João Brázio
5871c69f6f Add STEALTH_MODE toggle 2025-12-10 10:26:53 +00:00
João Brázio
802de27e03 Default to zero hop advert when booting 2025-12-09 13:21:22 +00:00
21 changed files with 144 additions and 212 deletions

View File

@@ -29,20 +29,6 @@ $ sh build.sh build-repeater-firmwares
Build all chat room server firmwares Build all chat room server firmwares
$ sh build.sh build-room-server-firmwares $ sh build.sh build-room-server-firmwares
Environment Variables:
DISABLE_DEBUG=1: Disables all debug logging flags (MESH_DEBUG, MESH_PACKET_LOGGING, etc.)
If not set, debug flags from variant platformio.ini files are used.
Examples:
Build without debug logging:
$ export FIRMWARE_VERSION=v1.0.0
$ export DISABLE_DEBUG=1
$ sh build.sh build-firmware RAK_4631_repeater
Build with debug logging (default, uses flags from variant files):
$ export FIRMWARE_VERSION=v1.0.0
$ sh build.sh build-firmware RAK_4631_repeater
EOF EOF
} }
@@ -82,13 +68,6 @@ get_pio_envs_ending_with_string() {
done done
} }
# disable all debug logging flags if DISABLE_DEBUG=1 is set
disable_debug_flags() {
if [ "$DISABLE_DEBUG" == "1" ]; then
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -UCFG_DEBUG -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL"
fi
}
# build firmware for the provided pio env in $1 # build firmware for the provided pio env in $1
build_firmware() { build_firmware() {
@@ -115,9 +94,6 @@ build_firmware() {
# add firmware version info to end of existing platformio build flags in environment vars # add firmware version info to end of existing platformio build flags in environment vars
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'" export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'"
# disable debug flags if requested
disable_debug_flags
# build firmware target # build firmware target
pio run -e $1 pio run -e $1

View File

@@ -227,7 +227,6 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
file.read((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84 file.read((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84
file.read((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85 file.read((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85
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.close(); file.close();
} }
@@ -262,7 +261,6 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84 file.write((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84
file.write((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85 file.write((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85
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.close(); file.close();
} }

View File

@@ -54,8 +54,6 @@
#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
#define CMD_SET_AUTOADD_CONFIG 58
#define CMD_GET_AUTOADD_CONFIG 59
// Stats sub-types for CMD_GET_STATS // Stats sub-types for CMD_GET_STATS
#define STATS_TYPE_CORE 0 #define STATS_TYPE_CORE 0
@@ -87,7 +85,6 @@
#define RESP_CODE_ADVERT_PATH 22 #define RESP_CODE_ADVERT_PATH 22
#define RESP_CODE_TUNING_PARAMS 23 #define RESP_CODE_TUNING_PARAMS 23
#define RESP_CODE_STATS 24 // v8+, second byte is stats type #define RESP_CODE_STATS 24 // v8+, second byte is stats type
#define RESP_CODE_AUTOADD_CONFIG 25
#define SEND_TIMEOUT_BASE_MILLIS 500 #define SEND_TIMEOUT_BASE_MILLIS 500
#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f #define FLOOD_SEND_TIMEOUT_FACTOR 16.0f
@@ -113,8 +110,6 @@
#define PUSH_CODE_BINARY_RESPONSE 0x8C #define PUSH_CODE_BINARY_RESPONSE 0x8C
#define PUSH_CODE_PATH_DISCOVERY_RESPONSE 0x8D #define PUSH_CODE_PATH_DISCOVERY_RESPONSE 0x8D
#define PUSH_CODE_CONTROL_DATA 0x8E // v8+ #define PUSH_CODE_CONTROL_DATA 0x8E // v8+
#define PUSH_CODE_CONTACT_DELETED 0x8F // used to notify client app of deleted contact when overwriting oldest
#define PUSH_CODE_CONTACTS_FULL 0x90 // used to notify client app that contacts storage is full
#define ERR_CODE_UNSUPPORTED_CMD 1 #define ERR_CODE_UNSUPPORTED_CMD 1
#define ERR_CODE_NOT_FOUND 2 #define ERR_CODE_NOT_FOUND 2
@@ -125,15 +120,6 @@
#define MAX_SIGN_DATA_LEN (8 * 1024) // 8K #define MAX_SIGN_DATA_LEN (8 * 1024) // 8K
// Auto-add config bitmask
// Bit 0: If set, overwrite oldest non-favourite contact when contacts file is full
// Bits 1-4: these indicate which contact types to auto-add when manual_contact_mode = 0x01
#define AUTO_ADD_OVERWRITE_OLDEST (1 << 0) // 0x01 - overwrite oldest non-favourite when full
#define AUTO_ADD_CHAT (1 << 1) // 0x02 - auto-add Chat (Companion) (ADV_TYPE_CHAT)
#define AUTO_ADD_REPEATER (1 << 2) // 0x04 - auto-add Repeater (ADV_TYPE_REPEATER)
#define AUTO_ADD_ROOM_SERVER (1 << 3) // 0x08 - auto-add Room Server (ADV_TYPE_ROOM)
#define AUTO_ADD_SENSOR (1 << 4) // 0x10 - auto-add Sensor (ADV_TYPE_SENSOR)
void MyMesh::writeOKFrame() { void MyMesh::writeOKFrame() {
uint8_t buf[1]; uint8_t buf[1];
buf[0] = RESP_CODE_OK; buf[0] = RESP_CODE_OK;
@@ -276,54 +262,9 @@ bool MyMesh::isAutoAddEnabled() const {
return (_prefs.manual_add_contacts & 1) == 0; return (_prefs.manual_add_contacts & 1) == 0;
} }
bool MyMesh::shouldAutoAddContactType(uint8_t contact_type) const {
if ((_prefs.manual_add_contacts & 1) == 0) {
return true;
}
uint8_t type_bit = 0;
switch (contact_type) {
case ADV_TYPE_CHAT:
type_bit = AUTO_ADD_CHAT;
break;
case ADV_TYPE_REPEATER:
type_bit = AUTO_ADD_REPEATER;
break;
case ADV_TYPE_ROOM:
type_bit = AUTO_ADD_ROOM_SERVER;
break;
case ADV_TYPE_SENSOR:
type_bit = AUTO_ADD_SENSOR;
break;
default:
return false; // Unknown type, don't auto-add
}
return (_prefs.autoadd_config & type_bit) != 0;
}
bool MyMesh::shouldOverwriteWhenFull() const {
return (_prefs.autoadd_config & AUTO_ADD_OVERWRITE_OLDEST) != 0;
}
void MyMesh::onContactOverwrite(const uint8_t* pub_key) {
if (_serial->isConnected()) {
out_frame[0] = PUSH_CODE_CONTACT_DELETED;
memcpy(&out_frame[1], pub_key, PUB_KEY_SIZE);
_serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE);
}
}
void MyMesh::onContactsFull() {
if (_serial->isConnected()) {
out_frame[0] = PUSH_CODE_CONTACTS_FULL;
_serial->writeFrame(out_frame, 1);
}
}
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) { void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
if (_serial->isConnected()) { if (_serial->isConnected()) {
if (!shouldAutoAddContactType(contact.type) && is_new) { if (!isAutoAddEnabled() && is_new) {
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
} else { } else {
out_frame[0] = PUSH_CODE_ADVERT; out_frame[0] = PUSH_CODE_ADVERT;
@@ -862,7 +803,6 @@ void MyMesh::begin(bool has_display) {
resetContacts(); resetContacts();
_store->loadContacts(this); _store->loadContacts(this);
bootstrapRTCfromContacts();
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
_store->loadChannels(this); _store->loadChannels(this);
@@ -1723,15 +1663,6 @@ void MyMesh::handleCmdFrame(size_t len) {
} else { } else {
writeErrFrame(ERR_CODE_TABLE_FULL); writeErrFrame(ERR_CODE_TABLE_FULL);
} }
} else if (cmd_frame[0] == CMD_SET_AUTOADD_CONFIG) {
_prefs.autoadd_config = cmd_frame[1];
savePrefs();
writeOKFrame();
} else if (cmd_frame[0] == CMD_GET_AUTOADD_CONFIG) {
int i = 0;
out_frame[i++] = RESP_CODE_AUTOADD_CONFIG;
out_frame[i++] = _prefs.autoadd_config;
_serial->writeFrame(out_frame, i);
} else { } else {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]);

View File

@@ -114,10 +114,6 @@ protected:
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override; void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;
bool isAutoAddEnabled() const override; bool isAutoAddEnabled() const override;
bool shouldAutoAddContactType(uint8_t type) const override;
bool shouldOverwriteWhenFull() const override;
void onContactsFull() override;
void onContactOverwrite(const uint8_t* pub_key) override;
bool 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) override; bool 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) override;
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override; void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
void onContactPathUpdated(const ContactInfo &contact) override; void onContactPathUpdated(const ContactInfo &contact) override;

View File

@@ -27,5 +27,4 @@ struct NodePrefs { // persisted to file
uint8_t buzzer_quiet; uint8_t buzzer_quiet;
uint8_t gps_enabled; // GPS enabled flag (0=disabled, 1=enabled) uint8_t gps_enabled; // GPS enabled flag (0=disabled, 1=enabled)
uint32_t gps_interval; // GPS read interval in seconds uint32_t gps_interval; // GPS read interval in seconds
uint8_t autoadd_config; // bitmask for auto-add contacts config
}; };

View File

@@ -390,6 +390,14 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
MESH_DEBUG_PRINTLN("allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet"); MESH_DEBUG_PRINTLN("allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet");
return false; return false;
} }
// Limit flood advert paket forwarding using a probabilistic reduction defined by P(h) = 0.308^(hops-1)
// https://github.com/meshcore-dev/MeshCore/issues/1223
double_t roll_dice = (double)rand() / RAND_MAX;
double_t forw_prob = pow(_prefs.flood_advert_base, packet->path_len - 1);
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood() && roll_dice > forw_prob)
return false;
// all other packets
return true; return true;
} }
@@ -711,6 +719,12 @@ bool MyMesh::onPeerPathRecv(mesh::Packet *packet, int sender_idx, const uint8_t
#define CTL_TYPE_NODE_DISCOVER_RESP 0x90 #define CTL_TYPE_NODE_DISCOVER_RESP 0x90
void MyMesh::onControlDataRecv(mesh::Packet* packet) { void MyMesh::onControlDataRecv(mesh::Packet* packet) {
if (!packet->payload) {
MESH_DEBUG_PRINTLN("onControlDataRecv: packet->payload is null");
return;
}
#if !defined(STEALTH_MODE)
uint8_t type = packet->payload[0] & 0xF0; // just test upper 4 bits uint8_t type = packet->payload[0] & 0xF0; // just test upper 4 bits
if (type == CTL_TYPE_NODE_DISCOVER_REQ && packet->payload_len >= 6 if (type == CTL_TYPE_NODE_DISCOVER_REQ && packet->payload_len >= 6
&& !_prefs.disable_fwd && discover_limiter.allow(rtc_clock.getCurrentTime()) && !_prefs.disable_fwd && discover_limiter.allow(rtc_clock.getCurrentTime())
@@ -739,6 +753,7 @@ void MyMesh::onControlDataRecv(mesh::Packet* packet) {
} }
} }
} }
#endif
} }
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,
@@ -781,8 +796,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.bw = LORA_BW; _prefs.bw = LORA_BW;
_prefs.cr = LORA_CR; _prefs.cr = LORA_CR;
_prefs.tx_power_dbm = LORA_TX_POWER; _prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs _prefs.advert_interval = DEF_LOCAL_ADVERT_INTERVAL;
_prefs.flood_advert_interval = 12; // 12 hours _prefs.flood_advert_interval = DEF_FLOOD_ADVERT_INTERVAL;
_prefs.flood_advert_base = 0.308f;
_prefs.flood_max = 64; _prefs.flood_max = 64;
_prefs.interference_threshold = 0; // disabled _prefs.interference_threshold = 0; // disabled
@@ -854,10 +870,14 @@ bool MyMesh::formatFileSystem() {
#endif #endif
} }
void MyMesh::sendSelfAdvertisement(int delay_millis) { void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
if (pkt) { if (pkt) {
sendFlood(pkt, delay_millis); if (flood) {
sendFlood(pkt, delay_millis);
} else {
sendZeroHop(pkt, delay_millis);
}
} else { } else {
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!"); MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
} }

View File

@@ -186,7 +186,7 @@ public:
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) override; void sendSelfAdvertisement(int delay_millis, bool flood = true) override;
void updateAdvertTimer() override; void updateAdvertTimer() override;
void updateFloodAdvertTimer() override; void updateFloodAdvertTimer() override;

View File

@@ -87,8 +87,10 @@ void setup() {
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
#endif #endif
// send out initial Advertisement to the mesh #if !defined(STEALTH_MODE) && !defined(NO_BOOT_ADVERT)
the_mesh.sendSelfAdvertisement(16000); // send out initial Zero Hop Advertisement to the mesh
the_mesh.sendSelfAdvertisement(16000, false);
#endif
} }
void loop() { void loop() {

View File

@@ -275,6 +275,15 @@ uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
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->path_len >= _prefs.flood_max) return false; if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false;
// Limit flood advert paket forwarding using a probabilistic reduction defined by P(h) = 0.308^(hops-1)
// https://github.com/meshcore-dev/MeshCore/issues/1223
double_t roll_dice = (double)rand() / RAND_MAX;
double_t forw_prob = pow(_prefs.flood_advert_base, packet->path_len - 1);
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood() && roll_dice > forw_prob)
return false;
// all other packets
return true; return true;
} }
@@ -611,8 +620,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.cr = LORA_CR; _prefs.cr = LORA_CR;
_prefs.tx_power_dbm = LORA_TX_POWER; _prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.disable_fwd = 1; _prefs.disable_fwd = 1;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs _prefs.advert_interval = DEF_LOCAL_ADVERT_INTERVAL;
_prefs.flood_advert_interval = 12; // 12 hours _prefs.flood_advert_interval = DEF_FLOOD_ADVERT_INTERVAL;
_prefs.flood_advert_base = 0.308f;
_prefs.flood_max = 64; _prefs.flood_max = 64;
_prefs.interference_threshold = 0; // disabled _prefs.interference_threshold = 0; // disabled
#ifdef ROOM_PASSWORD #ifdef ROOM_PASSWORD
@@ -675,10 +685,14 @@ bool MyMesh::formatFileSystem() {
#endif #endif
} }
void MyMesh::sendSelfAdvertisement(int delay_millis) { void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
if (pkt) { if (pkt) {
sendFlood(pkt, delay_millis); if (flood) {
sendFlood(pkt, delay_millis);
} else {
sendZeroHop(pkt, delay_millis);
}
} else { } else {
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!"); MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
} }

View File

@@ -177,7 +177,7 @@ public:
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) override; void sendSelfAdvertisement(int delay_millis, bool flood = true) override;
void updateAdvertTimer() override; void updateAdvertTimer() override;
void updateFloodAdvertTimer() override; void updateFloodAdvertTimer() override;

View File

@@ -76,8 +76,10 @@ void setup() {
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
#endif #endif
// send out initial Advertisement to the mesh #if !defined(STEALTH_MODE) && !defined(NO_BOOT_ADVERT)
the_mesh.sendSelfAdvertisement(16000); // send out initial Zero Hop Advertisement to the mesh
the_mesh.sendSelfAdvertisement(16000, false);
#endif
} }
void loop() { void loop() {

View File

@@ -718,7 +718,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
_prefs.bw = LORA_BW; _prefs.bw = LORA_BW;
_prefs.cr = LORA_CR; _prefs.cr = LORA_CR;
_prefs.tx_power_dbm = LORA_TX_POWER; _prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs _prefs.advert_interval = DEF_LOCAL_ADVERT_INTERVAL;
_prefs.flood_advert_interval = 0; // disabled _prefs.flood_advert_interval = 0; // disabled
_prefs.disable_fwd = true; _prefs.disable_fwd = true;
_prefs.flood_max = 64; _prefs.flood_max = 64;
@@ -788,10 +788,14 @@ void SensorMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t
revert_radio_at = futureMillis(2000 + timeout_mins*60*1000); // schedule when to revert radio params revert_radio_at = futureMillis(2000 + timeout_mins*60*1000); // schedule when to revert radio params
} }
void SensorMesh::sendSelfAdvertisement(int delay_millis) { void SensorMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh::Packet* pkt = createSelfAdvert(); mesh::Packet* pkt = createSelfAdvert();
if (pkt) { if (pkt) {
sendFlood(pkt, delay_millis); if (flood) {
sendFlood(pkt, delay_millis);
} else {
sendZeroHop(pkt, delay_millis);
}
} else { } else {
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!"); MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
} }

View File

@@ -60,7 +60,7 @@ public:
NodePrefs* getNodePrefs() { return &_prefs; } NodePrefs* getNodePrefs() { return &_prefs; }
void savePrefs() override { _cli.savePrefs(_fs); } void savePrefs() override { _cli.savePrefs(_fs); }
bool formatFileSystem() override; bool formatFileSystem() override;
void sendSelfAdvertisement(int delay_millis) override; void sendSelfAdvertisement(int delay_millis, bool flood = true) override;
void updateAdvertTimer() override; void updateAdvertTimer() override;
void updateFloodAdvertTimer() override; void updateFloodAdvertTimer() override;
void setLoggingOn(bool enable) override { } void setLoggingOn(bool enable) override { }

View File

@@ -110,8 +110,10 @@ void setup() {
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
#endif #endif
// send out initial Advertisement to the mesh #if !defined(STEALTH_MODE) && !defined(NO_BOOT_ADVERT)
the_mesh.sendSelfAdvertisement(16000); // send out initial Zero Hop Advertisement to the mesh
the_mesh.sendSelfAdvertisement(16000, false);
#endif
} }
void loop() { void loop() {

View File

@@ -23,12 +23,16 @@ lib_deps =
adafruit/RTClib @ ^2.1.3 adafruit/RTClib @ ^2.1.3
melopero/Melopero RV3028 @ ^1.1.0 melopero/Melopero RV3028 @ ^1.1.0
electroniccats/CayenneLPP @ 1.6.1 electroniccats/CayenneLPP @ 1.6.1
build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1 build_flags = -w -DNDEBUG
-D LORA_FREQ=869.525 -D LORA_FREQ=869.525
-D LORA_BW=250 -D LORA_BW=250
-D LORA_SF=11 -D LORA_SF=11
;
-D ENABLE_PRIVATE_KEY_IMPORT=1 ; NOTE: comment these out for more secure firmware -D ENABLE_PRIVATE_KEY_IMPORT=1 ; NOTE: comment these out for more secure firmware
-D ENABLE_PRIVATE_KEY_EXPORT=1 -D ENABLE_PRIVATE_KEY_EXPORT=1
;
-D RADIOLIB_STATIC_ONLY=1
-D RADIOLIB_GODMODE=1
-D RADIOLIB_EXCLUDE_CC1101=1 -D RADIOLIB_EXCLUDE_CC1101=1
-D RADIOLIB_EXCLUDE_RF69=1 -D RADIOLIB_EXCLUDE_RF69=1
-D RADIOLIB_EXCLUDE_SX1231=1 -D RADIOLIB_EXCLUDE_SX1231=1
@@ -43,6 +47,15 @@ build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
-D RADIOLIB_EXCLUDE_BELL=1 -D RADIOLIB_EXCLUDE_BELL=1
-D RADIOLIB_EXCLUDE_RTTY=1 -D RADIOLIB_EXCLUDE_RTTY=1
-D RADIOLIB_EXCLUDE_SSTV=1 -D RADIOLIB_EXCLUDE_SSTV=1
;
-D MIN_LOCAL_ADVERT_INTERVAL=60
-D MAX_LOCAL_ADVERT_INTERVAL=240
-D DEF_LOCAL_ADVERT_INTERVAL=1 ; default to 2 minutes for NEW installs
-D MIN_FLOOD_ADVERT_INTERVAL=3
-D MAX_FLOOD_ADVERT_INTERVAL=48
-D DEF_FLOOD_ADVERT_INTERVAL=12 ; default to 12 hours for NEW installs
; -D NO_BOOT_ADVERT=1 ; disable boot advertisement
; -D STEALTH_MODE=1 ; disable all advertisements and DISCOVER_REQ
build_src_filter = build_src_filter =
+<*.cpp> +<*.cpp>
+<helpers/*.cpp> +<helpers/*.cpp>

View File

@@ -55,54 +55,6 @@ void BaseChatMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) {
} }
} }
void BaseChatMesh::bootstrapRTCfromContacts() {
uint32_t latest = 0;
for (int i = 0; i < num_contacts; i++) {
if (contacts[i].lastmod > latest) {
latest = contacts[i].lastmod;
}
}
if (latest != 0) {
getRTCClock()->setCurrentTime(latest + 1);
}
}
ContactInfo* BaseChatMesh::allocateContactSlot() {
if (num_contacts < MAX_CONTACTS) {
return &contacts[num_contacts++];
} else if (shouldOverwriteWhenFull()) {
// Find oldest non-favourite contact by oldest lastmod timestamp
int oldest_idx = -1;
uint32_t oldest_lastmod = 0xFFFFFFFF;
for (int i = 0; i < num_contacts; i++) {
bool is_favourite = (contacts[i].flags & 0x01) != 0;
if (!is_favourite && contacts[i].lastmod < oldest_lastmod) {
oldest_lastmod = contacts[i].lastmod;
oldest_idx = i;
}
}
if (oldest_idx >= 0) {
onContactOverwrite(contacts[oldest_idx].id.pub_key);
return &contacts[oldest_idx];
}
}
return NULL; // no space, no overwrite or all contacts are all favourites
}
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
StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name));
ci.type = parser.getType();
if (parser.hasLatLon()) {
ci.gps_lat = parser.getIntLat();
ci.gps_lon = parser.getIntLon();
}
ci.last_advert_timestamp = timestamp;
ci.lastmod = getRTCClock()->getCurrentTime();
}
void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len) { void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len) {
AdvertDataParser parser(app_data, app_data_len); AdvertDataParser parser(app_data, app_data_len);
if (!(parser.isValid() && parser.hasName())) { if (!(parser.isValid() && parser.hasName())) {
@@ -135,37 +87,48 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id,
bool is_new = false; bool is_new = false;
if (from == NULL) { if (from == NULL) {
if (!shouldAutoAddContactType(parser.getType())) { if (!isAutoAddEnabled()) {
ContactInfo ci; ContactInfo ci;
populateContactFromAdvert(ci, id, parser, timestamp); memset(&ci, 0, sizeof(ci));
ci.id = id;
ci.out_path_len = -1; // initially out_path is unknown
StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name));
ci.type = parser.getType();
if (parser.hasLatLon()) {
ci.gps_lat = parser.getIntLat();
ci.gps_lon = parser.getIntLon();
}
ci.last_advert_timestamp = timestamp;
ci.lastmod = getRTCClock()->getCurrentTime();
onDiscoveredContact(ci, true, packet->path_len, packet->path); // let UI know onDiscoveredContact(ci, true, packet->path_len, packet->path); // let UI know
return; return;
} }
is_new = true; is_new = true;
from = allocateContactSlot(); if (num_contacts < MAX_CONTACTS) {
if (from == NULL) { from = &contacts[num_contacts++];
ContactInfo ci; from->id = id;
populateContactFromAdvert(ci, id, parser, timestamp); from->out_path_len = -1; // initially out_path is unknown
onDiscoveredContact(ci, true, packet->path_len, packet->path); from->gps_lat = 0; // initially unknown GPS loc
onContactsFull(); from->gps_lon = 0;
MESH_DEBUG_PRINTLN("onAdvertRecv: unable to allocate contact slot for new contact"); from->sync_since = 0;
from->shared_secret_valid = false; // ecdh shared_secret will be calculated later on demand
} else {
MESH_DEBUG_PRINTLN("onAdvertRecv: contacts table is full!");
return; return;
} }
populateContactFromAdvert(*from, id, parser, timestamp);
from->sync_since = 0;
from->shared_secret_valid = false;
} }
// update // update
StrHelper::strncpy(from->name, parser.getName(), sizeof(from->name)); StrHelper::strncpy(from->name, parser.getName(), sizeof(from->name));
from->type = parser.getType(); from->type = parser.getType();
if (parser.hasLatLon()) { if (parser.hasLatLon()) {
from->gps_lat = parser.getIntLat(); from->gps_lat = parser.getIntLat();
from->gps_lon = parser.getIntLon(); from->gps_lon = parser.getIntLon();
} }
from->last_advert_timestamp = timestamp; from->last_advert_timestamp = timestamp;
from->lastmod = getRTCClock()->getCurrentTime(); from->lastmod = getRTCClock()->getCurrentTime();
onDiscoveredContact(*from, is_new, packet->path_len, packet->path); // let UI know onDiscoveredContact(*from, is_new, packet->path_len, packet->path); // let UI know
} }
@@ -759,9 +722,10 @@ ContactInfo* BaseChatMesh::lookupContactByPubKey(const uint8_t* pub_key, int pre
} }
bool BaseChatMesh::addContact(const ContactInfo& contact) { bool BaseChatMesh::addContact(const ContactInfo& contact) {
ContactInfo* dest = allocateContactSlot(); if (num_contacts < MAX_CONTACTS) {
if (dest) { auto dest = &contacts[num_contacts++];
*dest = contact; *dest = contact;
dest->shared_secret_valid = false; // mark shared_secret as needing calculation dest->shared_secret_valid = false; // mark shared_secret as needing calculation
return true; // success return true; // success
} }

View File

@@ -88,17 +88,10 @@ protected:
memset(connections, 0, sizeof(connections)); memset(connections, 0, sizeof(connections));
} }
void bootstrapRTCfromContacts();
void resetContacts() { num_contacts = 0; } void resetContacts() { num_contacts = 0; }
void populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp);
ContactInfo* allocateContactSlot(); // helper to find slot for new contact
// 'UI' concepts, for sub-classes to implement // 'UI' concepts, for sub-classes to implement
virtual bool isAutoAddEnabled() const { return true; } virtual bool isAutoAddEnabled() const { return true; }
virtual bool shouldAutoAddContactType(uint8_t type) const { return true; }
virtual void onContactsFull() {};
virtual bool shouldOverwriteWhenFull() const { return false; }
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 void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0;
virtual ContactInfo* processAck(const uint8_t *data) = 0; virtual ContactInfo* processAck(const uint8_t *data) = 0;
virtual void onContactPathUpdated(const ContactInfo& contact) = 0; virtual void onContactPathUpdated(const ContactInfo& contact) = 0;

View File

@@ -81,7 +81,9 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162 file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166 file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170 file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
// 290 file.read((uint8_t *)&_prefs->flood_advert_base, sizeof(_prefs->flood_advert_base)); // 290
// 294
// sanitise bad pref values // sanitise bad pref values
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f); _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
@@ -108,6 +110,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
_prefs->gps_enabled = constrain(_prefs->gps_enabled, 0, 1); _prefs->gps_enabled = constrain(_prefs->gps_enabled, 0, 1);
_prefs->advert_loc_policy = constrain(_prefs->advert_loc_policy, 0, 2); _prefs->advert_loc_policy = constrain(_prefs->advert_loc_policy, 0, 2);
_prefs->flood_advert_base = constrain(_prefs->flood_advert_base, 0, 1);
file.close(); file.close();
} }
} }
@@ -165,14 +169,14 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162 file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166 file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170 file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
// 290 file.write((uint8_t *)&_prefs->flood_advert_base, sizeof(_prefs->flood_advert_base)); // 290
// 294
file.close(); file.close();
} }
} }
#define MIN_LOCAL_ADVERT_INTERVAL 60
void CommonCLI::savePrefs() { void CommonCLI::savePrefs() {
if (_prefs->advert_interval * 2 < MIN_LOCAL_ADVERT_INTERVAL) { if (_prefs->advert_interval * 2 < MIN_LOCAL_ADVERT_INTERVAL) {
_prefs->advert_interval = 0; // turn it off, now that device has been manually configured _prefs->advert_interval = 0; // turn it off, now that device has been manually configured
@@ -197,6 +201,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
if (memcmp(command, "reboot", 6) == 0) { if (memcmp(command, "reboot", 6) == 0) {
_board->reboot(); // doesn't return _board->reboot(); // doesn't return
} else if (memcmp(command, "advert", 6) == 0) { } else if (memcmp(command, "advert", 6) == 0) {
// Keep "advert" as flood for backward compatibility
_callbacks->sendSelfAdvertisement(1500); // longer delay, give CLI response time to be sent first _callbacks->sendSelfAdvertisement(1500); // longer delay, give CLI response time to be sent first
strcpy(reply, "OK - Advert sent"); strcpy(reply, "OK - Advert sent");
} else if (memcmp(command, "clock sync", 10) == 0) { } else if (memcmp(command, "clock sync", 10) == 0) {
@@ -217,7 +222,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
uint32_t now = getRTCClock()->getCurrentTime(); uint32_t now = getRTCClock()->getCurrentTime();
DateTime dt = DateTime(now); DateTime dt = DateTime(now);
sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year()); sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
} else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds) } else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds)
uint32_t secs = _atoi(&command[5]); uint32_t secs = _atoi(&command[5]);
uint32_t curr = getRTCClock()->getCurrentTime(); uint32_t curr = getRTCClock()->getCurrentTime();
if (secs > curr) { if (secs > curr) {
@@ -364,6 +369,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} else { } else {
sprintf(reply, "> %.3f", adc_mult); sprintf(reply, "> %.3f", adc_mult);
} }
} else if (memcmp(config, "flood.advert.base", 17) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->flood_advert_base));
} else { } else {
sprintf(reply, "??: %s", config); sprintf(reply, "??: %s", config);
} }
@@ -394,8 +401,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
strcpy(reply, "OK"); strcpy(reply, "OK");
} else if (memcmp(config, "flood.advert.interval ", 22) == 0) { } else if (memcmp(config, "flood.advert.interval ", 22) == 0) {
int hours = _atoi(&config[22]); int hours = _atoi(&config[22]);
if ((hours > 0 && hours < 3) || (hours > 48)) { if ((hours > 0 && hours < MIN_FLOOD_ADVERT_INTERVAL) || (hours > MAX_FLOOD_ADVERT_INTERVAL)) {
strcpy(reply, "Error: interval range is 3-48 hours"); sprintf(reply, "Error: interval range is %d-%d hours", MIN_FLOOD_ADVERT_INTERVAL,
MAX_FLOOD_ADVERT_INTERVAL);
} else { } else {
_prefs->flood_advert_interval = (uint8_t)(hours); _prefs->flood_advert_interval = (uint8_t)(hours);
_callbacks->updateFloodAdvertTimer(); _callbacks->updateFloodAdvertTimer();
@@ -404,8 +412,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} }
} else if (memcmp(config, "advert.interval ", 16) == 0) { } else if (memcmp(config, "advert.interval ", 16) == 0) {
int mins = _atoi(&config[16]); int mins = _atoi(&config[16]);
if ((mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) || (mins > 240)) { if ((mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) || (mins > MAX_LOCAL_ADVERT_INTERVAL)) {
sprintf(reply, "Error: interval range is %d-240 minutes", MIN_LOCAL_ADVERT_INTERVAL); sprintf(reply, "Error: interval range is %d-%d minutes",MIN_LOCAL_ADVERT_INTERVAL,
MAX_LOCAL_ADVERT_INTERVAL);
} else { } else {
_prefs->advert_interval = (uint8_t)(mins / 2); _prefs->advert_interval = (uint8_t)(mins / 2);
_callbacks->updateAdvertTimer(); _callbacks->updateAdvertTimer();
@@ -583,6 +592,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
_prefs->adc_multiplier = 0.0f; _prefs->adc_multiplier = 0.0f;
strcpy(reply, "Error: unsupported by this board"); strcpy(reply, "Error: unsupported by this board");
}; };
} else if (memcmp(config, "flood.advert.base ", 18) == 0) {
float f = atof(&config[18]);
if((f > 0) || (f<1)) {
_prefs->flood_advert_base = f;
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "Error: base must be between 0 and 1");
}
} else { } else {
sprintf(reply, "unknown config: %s", config); sprintf(reply, "unknown config: %s", config);
} }

View File

@@ -35,6 +35,7 @@ struct NodePrefs { // persisted to file
uint8_t flood_max; uint8_t flood_max;
uint8_t interference_threshold; uint8_t interference_threshold;
uint8_t agc_reset_interval; // secs / 4 uint8_t agc_reset_interval; // secs / 4
float flood_advert_base;
// Bridge settings // Bridge settings
uint8_t bridge_enabled; // boolean uint8_t bridge_enabled; // boolean
uint16_t bridge_delay; // milliseconds (default 500 ms) uint16_t bridge_delay; // milliseconds (default 500 ms)
@@ -60,7 +61,7 @@ public:
virtual const char* getBuildDate() = 0; virtual const char* getBuildDate() = 0;
virtual const char* getRole() = 0; virtual const char* getRole() = 0;
virtual bool formatFileSystem() = 0; virtual bool formatFileSystem() = 0;
virtual void sendSelfAdvertisement(int delay_millis) = 0; virtual void sendSelfAdvertisement(int delay_millis, bool flood = true) = 0;
virtual void updateAdvertTimer() = 0; virtual void updateAdvertTimer() = 0;
virtual void updateFloodAdvertTimer() = 0; virtual void updateFloodAdvertTimer() = 0;
virtual void setLoggingOn(bool enable) = 0; virtual void setLoggingOn(bool enable) = 0;

View File

@@ -323,7 +323,7 @@ lib_deps =
extends = Heltec_lora32_v3 extends = Heltec_lora32_v3
build_flags = build_flags =
${Heltec_lora32_v3.build_flags} ${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=350 -D MAX_CONTACTS=140
-D MAX_GROUP_CHANNELS=40 -D MAX_GROUP_CHANNELS=40
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1

View File

@@ -27,7 +27,6 @@ build_flags = ${nrf52_base.build_flags}
-D PIN_USER_BTN=0 -D PIN_USER_BTN=0
-D PIN_WIRE_SCL=7 -D PIN_WIRE_SCL=7
-D PIN_WIRE_SDA=6 -D PIN_WIRE_SDA=6
-UENV_INCLUDE_GPS
lib_deps = ${nrf52_base.lib_deps} lib_deps = ${nrf52_base.lib_deps}
${sensor_base.lib_deps} ${sensor_base.lib_deps}