From 2ede14e8dd4ebf20395adb6f148a1b67a779a377 Mon Sep 17 00:00:00 2001 From: Wouter Bijen Date: Tue, 3 Mar 2026 17:27:22 +0100 Subject: [PATCH] Advertise repeat capability via FEAT1 flags (#1906) Co-Authored-By: Claude Opus 4.6 --- examples/companion_radio/MyMesh.cpp | 15 +++++++++------ examples/simple_repeater/MyMesh.cpp | 3 ++- examples/simple_room_server/MyMesh.cpp | 3 ++- src/helpers/AdvertDataHelpers.h | 7 +++++-- src/helpers/BaseChatMesh.cpp | 6 ++++-- src/helpers/BaseChatMesh.h | 4 ++-- src/helpers/CommonCLI.cpp | 5 ++++- src/helpers/CommonCLI.h | 2 +- 8 files changed, 29 insertions(+), 16 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 1f71a9bc6c..9f1aff7d2e 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1111,11 +1111,12 @@ void MyMesh::handleCmdFrame(size_t len) { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { + uint16_t caps = _prefs.client_repeat ? ADVERT_CAP_REPEAT : 0; mesh::Packet* pkt; if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) { - pkt = createSelfAdvert(_prefs.node_name); + pkt = createSelfAdvert(_prefs.node_name, caps); } else { - pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); + pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon, caps); } if (pkt) { if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) @@ -1193,11 +1194,12 @@ void MyMesh::handleCmdFrame(size_t len) { } else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { if (len < 1 + PUB_KEY_SIZE) { // export SELF + uint16_t caps = _prefs.client_repeat ? ADVERT_CAP_REPEAT : 0; mesh::Packet* pkt; if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) { - pkt = createSelfAdvert(_prefs.node_name); + pkt = createSelfAdvert(_prefs.node_name, caps); } else { - pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); + pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon, caps); } if (pkt) { pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode @@ -2041,11 +2043,12 @@ void MyMesh::loop() { } bool MyMesh::advert() { + uint16_t caps = _prefs.client_repeat ? ADVERT_CAP_REPEAT : 0; mesh::Packet* pkt; if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) { - pkt = createSelfAdvert(_prefs.node_name); + pkt = createSelfAdvert(_prefs.node_name, caps); } else { - pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); + pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon, caps); } if (pkt) { sendZeroHop(pkt); diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 81c1dcb425..59308133e2 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -381,7 +381,8 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t mesh::Packet *MyMesh::createSelfAdvert() { uint8_t app_data[MAX_ADVERT_DATA_SIZE]; - uint8_t app_data_len = _cli.buildAdvertData(ADV_TYPE_REPEATER, app_data); + uint16_t caps = _prefs.disable_fwd ? 0 : ADVERT_CAP_REPEAT; + uint8_t app_data_len = _cli.buildAdvertData(ADV_TYPE_REPEATER, app_data, caps); return createAdvert(self_id, app_data, app_data_len); } diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 5451505a29..89ad181f60 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -116,7 +116,8 @@ bool MyMesh::processAck(const uint8_t *data) { mesh::Packet *MyMesh::createSelfAdvert() { uint8_t app_data[MAX_ADVERT_DATA_SIZE]; - uint8_t app_data_len = _cli.buildAdvertData(ADV_TYPE_ROOM, app_data); + uint16_t caps = _prefs.disable_fwd ? 0 : ADVERT_CAP_REPEAT; + uint8_t app_data_len = _cli.buildAdvertData(ADV_TYPE_ROOM, app_data, caps); return createAdvert(self_id, app_data, app_data_len); } diff --git a/src/helpers/AdvertDataHelpers.h b/src/helpers/AdvertDataHelpers.h index abe14cbd00..f625b8f01f 100644 --- a/src/helpers/AdvertDataHelpers.h +++ b/src/helpers/AdvertDataHelpers.h @@ -12,10 +12,13 @@ //FUTURE: 5..15 #define ADV_LATLON_MASK 0x10 -#define ADV_FEAT1_MASK 0x20 // FUTURE +#define ADV_FEAT1_MASK 0x20 #define ADV_FEAT2_MASK 0x40 // FUTURE #define ADV_NAME_MASK 0x80 +// FEAT1 bits +#define ADVERT_CAP_REPEAT 0x0001 // node forwards packets + class AdvertDataBuilder { uint8_t _type; bool _has_loc; @@ -26,7 +29,7 @@ class AdvertDataBuilder { public: AdvertDataBuilder(uint8_t adv_type) : _type(adv_type), _name(NULL), _has_loc(false) { } AdvertDataBuilder(uint8_t adv_type, const char* name) : _type(adv_type), _name(name), _has_loc(false) { } - AdvertDataBuilder(uint8_t adv_type, const char* name, double lat, double lon) : + AdvertDataBuilder(uint8_t adv_type, const char* name, double lat, double lon) : _type(adv_type), _name(name), _has_loc(true), _lat(lat * 1E6), _lon(lon * 1E6) { } void setFeat1(uint16_t extra) { _extra1 = extra; } diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 33d7edbee4..4201a317de 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -16,22 +16,24 @@ void BaseChatMesh::sendFloodScoped(const mesh::GroupChannel& channel, mesh::Pack sendFlood(pkt, delay_millis); } -mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name) { +mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name, uint16_t feat1) { uint8_t app_data[MAX_ADVERT_DATA_SIZE]; uint8_t app_data_len; { AdvertDataBuilder builder(ADV_TYPE_CHAT, name); + if (feat1) builder.setFeat1(feat1); app_data_len = builder.encodeTo(app_data); } return createAdvert(self_id, app_data, app_data_len); } -mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name, double lat, double lon) { +mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name, double lat, double lon, uint16_t feat1) { uint8_t app_data[MAX_ADVERT_DATA_SIZE]; uint8_t app_data_len; { AdvertDataBuilder builder(ADV_TYPE_CHAT, name, lat, lon); + if (feat1) builder.setFeat1(feat1); app_data_len = builder.encodeTo(app_data); } diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index ab90d581be..199ac746e9 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -143,8 +143,8 @@ class BaseChatMesh : public mesh::Mesh { void checkConnections(); public: - mesh::Packet* createSelfAdvert(const char* name); - mesh::Packet* createSelfAdvert(const char* name, double lat, double lon); + mesh::Packet* createSelfAdvert(const char* name, uint16_t feat1 = 0); + mesh::Packet* createSelfAdvert(const char* name, double lat, double lon, uint16_t feat1 = 0); int sendMessage(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& expected_ack, uint32_t& est_timeout); int sendCommandData(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& est_timeout); bool sendGroupMessage(uint32_t timestamp, mesh::GroupChannel& channel, const char* sender_name, const char* text, int text_len); diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index fd63127348..7d3fa1beec 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -183,15 +183,18 @@ void CommonCLI::savePrefs() { _callbacks->savePrefs(); } -uint8_t CommonCLI::buildAdvertData(uint8_t node_type, uint8_t* app_data) { +uint8_t CommonCLI::buildAdvertData(uint8_t node_type, uint8_t* app_data, uint16_t feat1) { if (_prefs->advert_loc_policy == ADVERT_LOC_NONE) { AdvertDataBuilder builder(node_type, _prefs->node_name); + if (feat1) builder.setFeat1(feat1); return builder.encodeTo(app_data); } else if (_prefs->advert_loc_policy == ADVERT_LOC_SHARE) { AdvertDataBuilder builder(node_type, _prefs->node_name, _sensors->node_lat, _sensors->node_lon); + if (feat1) builder.setFeat1(feat1); return builder.encodeTo(app_data); } else { AdvertDataBuilder builder(node_type, _prefs->node_name, _prefs->node_lat, _prefs->node_lon); + if (feat1) builder.setFeat1(feat1); return builder.encodeTo(app_data); } } diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 1e454ec290..e27fcd5f9c 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -110,5 +110,5 @@ class CommonCLI { void loadPrefs(FILESYSTEM* _fs); void savePrefs(FILESYSTEM* _fs); void handleCommand(uint32_t sender_timestamp, const 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, uint16_t feat1 = 0); };