LINK payloads now look like BOB says Hi to CY iter=0.
Sender/recipient use board IDs for easier log aggregation. Iteration count is still included and increments per peer. Send cadence is now once per minute at the node’s allocated slot only. Removed the previous slot + 30s second send. Removed noisy app-internal diagnostics like APP LINK..., APP RX..., and TX LINK SKIP. Set Reticulum library logging to LOG_WARNING, which suppresses heap/path-store/entries/byte-count style diagnostics while preserving warnings/errors. Fixed inherited physical slot label Fay to Flo. Updated the README with the message cadence and examples
This commit is contained in:
parent
2a6fef41c7
commit
23fbc569c6
2 changed files with 99 additions and 69 deletions
|
|
@ -17,6 +17,19 @@ There is no simulated BOB/CY physical block in this exercise. `SIM_PHY_ENVELOPE`
|
|||
|
||||
Exercise 205 does not intentionally tear down Links after a message count. A Link is reused while it remains active. If a Link becomes stale or closes, the unit clears local state and attempts to recreate the outbound Link.
|
||||
|
||||
Each unit sends one Link message per active peer per minute at its allocated second:
|
||||
|
||||
```text
|
||||
AMY: 04 BOB: 08 CY: 12 DAN: 16
|
||||
ED: 20 FLO: 24 GUY: 28
|
||||
```
|
||||
|
||||
The message payload uses board IDs and includes an iteration counter:
|
||||
|
||||
```text
|
||||
BOB says Hi to CY iter=0
|
||||
```
|
||||
|
||||
The outbound Link retry budget is:
|
||||
|
||||
```text
|
||||
|
|
@ -41,13 +54,15 @@ RX ANNOUNCE: label=Cy hash=<destination hash> phy=Cy(2)
|
|||
TX LINKREQUEST: opening link to Cy slot=19 attempt=1/3
|
||||
LINK ACTIVE: initiator link established to Cy hash=<link hash>
|
||||
RX LINK: inbound link established hash=<link hash> phy=Bob(1)
|
||||
TX LINK: Hi from Bob iter=0 to=Cy via=outbound hash=<link hash> status=2
|
||||
RX LINK: Hi from Cy iter=0 to=Bob | phy=Cy(2) RSSI=... SNR=...
|
||||
TX LINK: BOB says Hi to CY iter=0 via=outbound hash=<link hash> status=2
|
||||
RX LINK: CY says Hi to BOB iter=0 | phy=Cy(2) RSSI=... SNR=...
|
||||
LINK RETRY: no establishment after 60000 ms; retrying Cy attempts=1/3
|
||||
LINK FAILED: peer=Cy attempts=3 window_ms=... waiting_for_announce=1
|
||||
LINK RETRY RESET: fresh announce from Cy
|
||||
```
|
||||
|
||||
Reticulum library logging is set to warning level in this exercise. Heap, path-store, entries, and byte-count diagnostics are intentionally suppressed so serial logs remain focused on field-test results.
|
||||
|
||||
# Build, Upload, And Monitor
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@
|
|||
#define SIM_PHY_BLOCK_BOB_CY 0
|
||||
#endif
|
||||
|
||||
#ifndef EX205_RNS_TRACE
|
||||
#define EX205_RNS_TRACE 0
|
||||
#endif
|
||||
#ifndef MR_LINKFWD_DELAY_MS
|
||||
#define MR_LINKFWD_DELAY_MS 0
|
||||
#endif
|
||||
|
|
@ -127,7 +124,6 @@ struct PeerState {
|
|||
uint32_t last_tx_ms = 0;
|
||||
uint32_t tx_iter = 0;
|
||||
uint8_t last_tx_second = 255;
|
||||
uint8_t last_skip_second = 255;
|
||||
};
|
||||
|
||||
static PeerState peers[MAX_PEERS];
|
||||
|
|
@ -142,12 +138,66 @@ static const char* node_label_for_slot(uint8_t slot) {
|
|||
case 2: return "Cy";
|
||||
case 3: return "Dan";
|
||||
case 4: return "Ed";
|
||||
case 5: return "Fay";
|
||||
case 5: return "Flo";
|
||||
case 6: return "Guy";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* board_id_for_label(const String& label) {
|
||||
if (label == "Amy") {
|
||||
return "AMY";
|
||||
}
|
||||
if (label == "Bob") {
|
||||
return "BOB";
|
||||
}
|
||||
if (label == "Cy") {
|
||||
return "CY";
|
||||
}
|
||||
if (label == "Dan") {
|
||||
return "DAN";
|
||||
}
|
||||
if (label == "Ed") {
|
||||
return "ED";
|
||||
}
|
||||
if (label == "Flo") {
|
||||
return "FLO";
|
||||
}
|
||||
if (label == "Guy") {
|
||||
return "GUY";
|
||||
}
|
||||
return label.c_str();
|
||||
}
|
||||
|
||||
static bool is_local_name(const String& value) {
|
||||
return value == NODE_LABEL || value == BOARD_ID;
|
||||
}
|
||||
|
||||
static String peer_label_from_name(const String& value) {
|
||||
if (value == "AMY") {
|
||||
return "Amy";
|
||||
}
|
||||
if (value == "BOB") {
|
||||
return "Bob";
|
||||
}
|
||||
if (value == "CY") {
|
||||
return "Cy";
|
||||
}
|
||||
if (value == "DAN") {
|
||||
return "Dan";
|
||||
}
|
||||
if (value == "ED") {
|
||||
return "Ed";
|
||||
}
|
||||
if (value == "FLO") {
|
||||
return "Flo";
|
||||
}
|
||||
if (value == "GUY") {
|
||||
return "Guy";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR on_pps_edge() {
|
||||
last_pps_ms = millis();
|
||||
}
|
||||
|
|
@ -665,7 +715,6 @@ static void clear_peer_slot(uint8_t index) {
|
|||
peers[index].last_tx_ms = 0;
|
||||
peers[index].tx_iter = 0;
|
||||
peers[index].last_tx_second = 255;
|
||||
peers[index].last_skip_second = 255;
|
||||
}
|
||||
|
||||
static int ensure_peer_for_label(const String& label) {
|
||||
|
|
@ -681,6 +730,11 @@ static int ensure_peer_for_label(const String& label) {
|
|||
}
|
||||
|
||||
static String parse_sender_label(const String& text) {
|
||||
const int says_pos = text.indexOf(" says ");
|
||||
if (says_pos > 0) {
|
||||
return text.substring(0, says_pos);
|
||||
}
|
||||
|
||||
const int from_pos = text.indexOf("from ");
|
||||
if (from_pos < 0) {
|
||||
return "";
|
||||
|
|
@ -694,6 +748,16 @@ static String parse_sender_label(const String& text) {
|
|||
}
|
||||
|
||||
static String parse_recipient_label(const String& text) {
|
||||
const int says_hi_to_pos = text.indexOf(" says Hi to ");
|
||||
if (says_hi_to_pos >= 0) {
|
||||
const int start = says_hi_to_pos + 12;
|
||||
int end = text.indexOf(' ', start);
|
||||
if (end < 0) {
|
||||
end = text.length();
|
||||
}
|
||||
return text.substring(start, end);
|
||||
}
|
||||
|
||||
const int to_pos = text.indexOf("to=");
|
||||
if (to_pos < 0) {
|
||||
return "";
|
||||
|
|
@ -707,14 +771,6 @@ static String parse_recipient_label(const String& text) {
|
|||
}
|
||||
|
||||
static void attach_link_callbacks(RNS::Link& link) {
|
||||
if (link) {
|
||||
Serial.printf("APP LINK CALLBACKS: attach hash=%s status=%u initiator=%u\r\n",
|
||||
link.hash().toHex().c_str(),
|
||||
(unsigned)link.status(),
|
||||
link.initiator() ? 1U : 0U);
|
||||
} else {
|
||||
Serial.println("APP LINK CALLBACKS: attach skipped null link");
|
||||
}
|
||||
link.set_packet_callback(on_link_packet);
|
||||
link.set_link_closed_callback(on_link_closed);
|
||||
}
|
||||
|
|
@ -728,21 +784,13 @@ static void on_link_packet(const RNS::Bytes& data, const RNS::Packet& packet) {
|
|||
String text = data.toString().c_str();
|
||||
String sender = parse_sender_label(text);
|
||||
String recipient = parse_recipient_label(text);
|
||||
Serial.printf("APP RX LINK ENTER: link=%s status=%u initiator=%u peer_index=%d sender=%s recipient=%s text=%s\r\n",
|
||||
packet.link() ? packet.link().hash().toHex().c_str() : "(none)",
|
||||
packet.link() ? (unsigned)packet.link().status() : 255U,
|
||||
packet.link() && packet.link().initiator() ? 1U : 0U,
|
||||
peer_index,
|
||||
sender.c_str(),
|
||||
recipient.c_str(),
|
||||
text.c_str());
|
||||
if (sender == NODE_LABEL || (recipient.length() > 0 && recipient != NODE_LABEL)) {
|
||||
Serial.printf("RX LINK ignored: self_or_wrong_recipient text=%s\r\n", text.c_str());
|
||||
const String sender_label = peer_label_from_name(sender);
|
||||
if (is_local_name(sender) || (recipient.length() > 0 && !is_local_name(recipient))) {
|
||||
return;
|
||||
}
|
||||
if (peer_index >= 0 && peers[peer_index].label.length() == 0 &&
|
||||
sender.length() > 0 && sender != NODE_LABEL) {
|
||||
const int existing_index = find_peer_by_label(sender);
|
||||
sender.length() > 0 && !is_local_name(sender)) {
|
||||
const int existing_index = find_peer_by_label(sender_label);
|
||||
if (existing_index >= 0 && existing_index != peer_index) {
|
||||
if (packet.link()) {
|
||||
peers[existing_index].inbound_link = packet.link();
|
||||
|
|
@ -752,12 +800,12 @@ static void on_link_packet(const RNS::Bytes& data, const RNS::Packet& packet) {
|
|||
clear_peer_slot((uint8_t)peer_index);
|
||||
peer_index = existing_index;
|
||||
} else {
|
||||
peers[peer_index].label = sender;
|
||||
peers[peer_index].label = sender_label;
|
||||
}
|
||||
}
|
||||
if (peer_index < 0) {
|
||||
if (sender.length() > 0 && sender != NODE_LABEL) {
|
||||
peer_index = ensure_peer_for_label(sender);
|
||||
if (sender.length() > 0 && !is_local_name(sender)) {
|
||||
peer_index = ensure_peer_for_label(sender_label);
|
||||
if (peer_index >= 0 && packet.link()) {
|
||||
peers[peer_index].inbound_link = packet.link();
|
||||
peers[peer_index].inbound_active = true;
|
||||
|
|
@ -814,11 +862,6 @@ static void on_link_closed(RNS::Link& link) {
|
|||
|
||||
static void on_outbound_link_established(RNS::Link& link) {
|
||||
int peer_index = find_peer_by_link_hash(link.hash());
|
||||
Serial.printf("APP LINK ESTABLISHED CB: direction=outbound hash=%s status=%u initiator=%u peer_index=%d\r\n",
|
||||
link.hash().toHex().c_str(),
|
||||
(unsigned)link.status(),
|
||||
link.initiator() ? 1U : 0U,
|
||||
peer_index);
|
||||
if (peer_index >= 0) {
|
||||
peers[peer_index].outbound_link = link;
|
||||
attach_link_callbacks(peers[peer_index].outbound_link);
|
||||
|
|
@ -843,11 +886,6 @@ static void on_inbound_link_established(RNS::Link& link) {
|
|||
if (peer_index < 0) {
|
||||
peer_index = first_free_peer_slot();
|
||||
}
|
||||
Serial.printf("APP LINK ESTABLISHED CB: direction=inbound hash=%s status=%u initiator=%u peer_index=%d\r\n",
|
||||
link.hash().toHex().c_str(),
|
||||
(unsigned)link.status(),
|
||||
link.initiator() ? 1U : 0U,
|
||||
peer_index);
|
||||
if (peer_index >= 0) {
|
||||
peers[peer_index].inbound_link = link;
|
||||
attach_link_callbacks(peers[peer_index].inbound_link);
|
||||
|
|
@ -922,11 +960,10 @@ static void print_config() {
|
|||
Serial.printf("LoRa: freq=%.1f BW=%.1f SF=%d CR=%d sync=0x%02x txp=%d\r\n",
|
||||
(double)LORA_FREQ_MHZ, (double)LORA_BW_KHZ, (int)LORA_SF,
|
||||
(int)LORA_CR, (int)LORA_SYNC_WORD, (int)LORA_TX_POWER_DBM);
|
||||
Serial.printf("Sim: phy_envelope=%d phy_block_bob_cy=%d node_slot=%d rns_trace=%d linkfwd_delay_ms=%u transport=1\r\n",
|
||||
Serial.printf("Sim: phy_envelope=%d phy_block_bob_cy=%d node_slot=%d rns_log=warning linkfwd_delay_ms=%u transport=1\r\n",
|
||||
(int)SIM_PHY_ENVELOPE,
|
||||
(int)SIM_PHY_BLOCK_BOB_CY,
|
||||
(int)NODE_SLOT_INDEX,
|
||||
(int)EX205_RNS_TRACE,
|
||||
(unsigned)MR_LINKFWD_DELAY_MS);
|
||||
Serial.printf("Announce: startup=1 second=%lu repeat=%lu seconds\r\n",
|
||||
(unsigned long)ANNOUNCEMENT_2,
|
||||
|
|
@ -1016,12 +1053,6 @@ static void maybe_open_link(const DateTime& rtc_now, bool have_rtc_now) {
|
|||
continue;
|
||||
}
|
||||
if (peer.outbound_active || (peer.outbound_link && peer.outbound_link.status() == RNS::Type::Link::ACTIVE)) {
|
||||
if (!peer.outbound_active) {
|
||||
Serial.printf("APP LINK STATE: outbound already active peer=%s hash=%s status=%u\r\n",
|
||||
peer.label.c_str(),
|
||||
peer.outbound_link.hash().toHex().c_str(),
|
||||
(unsigned)peer.outbound_link.status());
|
||||
}
|
||||
peer.outbound_active = true;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1151,11 +1182,7 @@ void setup() {
|
|||
|
||||
Serial.println();
|
||||
Serial.println("Exercise 205: sustained transport Links");
|
||||
#if EX205_RNS_TRACE
|
||||
RNS::loglevel(RNS::LOG_TRACE);
|
||||
#else
|
||||
RNS::loglevel(RNS::LOG_NOTICE);
|
||||
#endif
|
||||
RNS::loglevel(RNS::LOG_WARNING);
|
||||
|
||||
(void)tbeam_supreme::initPmuForPeripherals(pmu, &Serial);
|
||||
tbeam::DisplayConfig display_config;
|
||||
|
|
@ -1196,8 +1223,7 @@ void loop() {
|
|||
|
||||
maybe_send_scheduled_announce();
|
||||
const uint8_t send_slot = node_send_slot_second();
|
||||
const uint8_t second_slot = (uint8_t)((send_slot + 30U) % 60U);
|
||||
if (have_rtc_now && (rtc_now.second == send_slot || rtc_now.second == second_slot)) {
|
||||
if (have_rtc_now && rtc_now.second == send_slot) {
|
||||
for (uint8_t i = 0; i < MAX_PEERS; ++i) {
|
||||
PeerState& peer = peers[i];
|
||||
if (peer.label.length() == 0 || peer.last_tx_second == rtc_now.second) {
|
||||
|
|
@ -1213,24 +1239,13 @@ void loop() {
|
|||
link = &peer.inbound_link;
|
||||
}
|
||||
if (!link) {
|
||||
if (peer.last_skip_second != rtc_now.second) {
|
||||
peer.last_skip_second = rtc_now.second;
|
||||
Serial.printf("TX LINK SKIP: peer=%s outbound=%u outbound_status=%u inbound=%u inbound_status=%u attempted=%u active_out=%u active_in=%u\r\n",
|
||||
peer.label.c_str(),
|
||||
peer.outbound_link ? 1U : 0U,
|
||||
peer.outbound_link ? (unsigned)peer.outbound_link.status() : 255U,
|
||||
peer.inbound_link ? 1U : 0U,
|
||||
peer.inbound_link ? (unsigned)peer.inbound_link.status() : 255U,
|
||||
peer.outbound_attempted ? 1U : 0U,
|
||||
peer.outbound_active ? 1U : 0U,
|
||||
peer.inbound_active ? 1U : 0U);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
peer.last_tx_second = rtc_now.second;
|
||||
peer.last_tx_ms = now;
|
||||
String message = String("Hi from ") + NODE_LABEL + " iter=" + String(peer.tx_iter++) + " to=" + peer.label;
|
||||
const char* recipient = board_id_for_label(peer.label);
|
||||
String message = String(BOARD_ID) + " says Hi to " + recipient + " iter=" + String(peer.tx_iter++);
|
||||
Serial.printf("TX LINK: %s via=%s hash=%s status=%u\r\n",
|
||||
message.c_str(),
|
||||
link == &peer.outbound_link ? "outbound" : "inbound",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue