diff --git a/exercises/205_sustained_link/README.md b/exercises/205_sustained_link/README.md index 5d0f796..37ba8de 100644 --- a/exercises/205_sustained_link/README.md +++ b/exercises/205_sustained_link/README.md @@ -50,10 +50,11 @@ Substantive events retain the Exercise 204 style so multi-unit log parsing can c ```text TX ANNOUNCE: Bob -RX ANNOUNCE: label=Cy hash= phy=Cy(2) +RX PHY: phy=2 len=... RSSI=-73.5 SNR=9.2 frames=... +RX ANNOUNCE: label=Cy hash= phy=Cy(2) RSSI=-73.5 SNR=9.2 TX LINKREQUEST: opening link to Cy slot=19 attempt=1/3 LINK ACTIVE: initiator link established to Cy hash= -RX LINK: inbound link established hash= phy=Bob(1) +RX LINK: inbound link established hash= phy=Bob(1) RSSI=-74.0 SNR=8.8 TX LINK: BOB says Hi to CY iter=0 via=outbound 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 @@ -61,6 +62,19 @@ LINK FAILED: peer=Cy attempts=3 window_ms=... waiting_for_announce=1 LINK RETRY RESET: fresh announce from Cy ``` +`RX PHY` is emitted once per accepted LoRa frame before Reticulum decrypts or routes it. It is the broadest signal-strength record and includes frames that become announces, link setup packets, encrypted Link payloads, keepalives, or proofs. `RX PHY BAD` and `SIM PHY DROP` also include RSSI/SNR when malformed or intentionally blocked frames are seen. + +The following `RNS...` prefixes are generated by the linked microReticulum tree when Arduino link instrumentation is enabled: + +| Prefix | Source | Meaning | +| --- | --- | --- | +| `RNSLINKREQ` | `microReticulum/src/Link.cpp` | Incoming Link request validation accepted; shows the new link ID, owner destination, hops, status, initiator flag, interface, and whether the app has a link-established callback. | +| `RNSPROOF_DELAY` | `microReticulum/src/Link.cpp` | Link proof send path is applying the configured proof delay before transmitting the proof packet. | +| `RNSPROOF` | `microReticulum/src/Link.cpp` and transport proof probes | Link proof validation and proof forwarding diagnostics, including signature validity, state transitions, interface checks, and exceptions. | +| `RNSLRRTT` | `microReticulum/src/Link.cpp` | Link request round-trip-time packet handling. This is part of Link establishment and marks decrypt, active, and owner callback events. | +| `RNSLINKRX` | `microReticulum/src/Link.cpp` | Link-associated packet receive path. It logs packet context, decrypt success, app packet callback entry/return, no-callback cases, and LRRTT dispatch. | +| `RNSDEC` | `microReticulum/src/Link.cpp` | Link encryption/decryption token diagnostics, including encrypt attempts, decrypt attempts, and decrypt failure class. | + 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 diff --git a/exercises/205_sustained_link/src/TBeamSupremeLoRaInterface.cpp b/exercises/205_sustained_link/src/TBeamSupremeLoRaInterface.cpp index 8735459..f1deca9 100644 --- a/exercises/205_sustained_link/src/TBeamSupremeLoRaInterface.cpp +++ b/exercises/205_sustained_link/src/TBeamSupremeLoRaInterface.cpp @@ -103,6 +103,12 @@ void TBeamSupremeLoRaInterface::loop() { _radio->startReceive(); return; } + Serial.printf("RX PHY: phy=%u len=%d RSSI=%.1f SNR=%.1f frames=%lu\r\n", + (unsigned)physical_tx, + len, + _last_rssi, + _last_snr, + (unsigned long)_phy_rx_frames); if (len <= 1) { _radio->startReceive(); return; @@ -158,21 +164,33 @@ bool TBeamSupremeLoRaInterface::unpack_frame(uint8_t* frame, int& len, uint8_t& #if SIM_PHY_ENVELOPE if (len < PHY_ENVELOPE_LEN + 1) { ++_phy_bad_frames; + Serial.printf("RX PHY BAD: reason=short len=%d RSSI=%.1f SNR=%.1f bad=%lu\r\n", + len, + _last_rssi, + _last_snr, + (unsigned long)_phy_bad_frames); DEBUGF("SIM PHY malformed: short frame len=%d", len); return false; } if (frame[0] != PHY_MAGIC_0 || frame[1] != PHY_MAGIC_1 || frame[2] != PHY_VERSION) { ++_phy_bad_frames; + Serial.printf("RX PHY BAD: reason=envelope len=%d RSSI=%.1f SNR=%.1f bad=%lu\r\n", + len, + _last_rssi, + _last_snr, + (unsigned long)_phy_bad_frames); DEBUGF("SIM PHY malformed: bad envelope len=%d", len); return false; } physical_tx = frame[3]; if (should_drop_physical_tx(physical_tx)) { ++_phy_blocked_frames; - Serial.printf("SIM PHY DROP: rx=%u tx=%u len=%d blocked=%lu\r\n", + Serial.printf("SIM PHY DROP: rx=%u tx=%u len=%d RSSI=%.1f SNR=%.1f blocked=%lu\r\n", (unsigned)NODE_SLOT_INDEX, (unsigned)physical_tx, len, + _last_rssi, + _last_snr, (unsigned long)_phy_blocked_frames); DEBUGF("SIM PHY DROP: rx=%u tx=%u len=%d", (unsigned)NODE_SLOT_INDEX, diff --git a/exercises/205_sustained_link/src/main.cpp b/exercises/205_sustained_link/src/main.cpp index ef667e9..a024e56 100644 --- a/exercises/205_sustained_link/src/main.cpp +++ b/exercises/205_sustained_link/src/main.cpp @@ -123,7 +123,7 @@ struct PeerState { uint32_t last_rx_ms = 0; uint32_t last_tx_ms = 0; uint32_t tx_iter = 0; - uint8_t last_tx_second = 255; + uint32_t last_tx_minute = 0xFFFFFFFFUL; }; static PeerState peers[MAX_PEERS]; @@ -714,7 +714,7 @@ static void clear_peer_slot(uint8_t index) { peers[index].last_rx_ms = 0; peers[index].last_tx_ms = 0; peers[index].tx_iter = 0; - peers[index].last_tx_second = 255; + peers[index].last_tx_minute = 0xFFFFFFFFUL; } static int ensure_peer_for_label(const String& label) { @@ -893,10 +893,14 @@ static void on_inbound_link_established(RNS::Link& link) { peers[peer_index].last_link_active_ms = millis(); } uint8_t physical_tx = lora_impl ? lora_impl->last_physical_tx() : 255; - Serial.printf("RX LINK: inbound link established hash=%s phy=%s(%u)\r\n", + float rssi = lora_impl ? lora_impl->last_rssi() : 0.0f; + float snr = lora_impl ? lora_impl->last_snr() : 0.0f; + Serial.printf("RX LINK: inbound link established hash=%s phy=%s(%u) RSSI=%.1f SNR=%.1f\r\n", link.hash().toHex().c_str(), node_label_for_slot(physical_tx), - (unsigned)physical_tx); + (unsigned)physical_tx, + rssi, + snr); show_status("LINK ACTIVE", "inbound", link.hash().toHex().c_str()); } @@ -941,11 +945,15 @@ class LinkAnnounceHandler : public RNS::AnnounceHandler { } uint8_t physical_tx = lora_impl ? lora_impl->last_physical_tx() : 255; - Serial.printf("RX ANNOUNCE: label=%s hash=%s phy=%s(%u)\r\n", + float rssi = lora_impl ? lora_impl->last_rssi() : 0.0f; + float snr = lora_impl ? lora_impl->last_snr() : 0.0f; + Serial.printf("RX ANNOUNCE: label=%s hash=%s phy=%s(%u) RSSI=%.1f SNR=%.1f\r\n", peers[peer_index].label.c_str(), peers[peer_index].destination_hash.toHex().c_str(), node_label_for_slot(physical_tx), - (unsigned)physical_tx); + (unsigned)physical_tx, + rssi, + snr); show_status("RX ANNOUNCE", peers[peer_index].label.c_str(), peers[peer_index].destination_hash.toHex().c_str()); } }; @@ -1224,9 +1232,10 @@ void loop() { maybe_send_scheduled_announce(); const uint8_t send_slot = node_send_slot_second(); if (have_rtc_now && rtc_now.second == send_slot) { + const uint32_t tx_minute = (uint32_t)(to_epoch_seconds(rtc_now) / 60LL); 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) { + if (peer.label.length() == 0 || peer.last_tx_minute == tx_minute) { continue; } @@ -1242,7 +1251,7 @@ void loop() { continue; } - peer.last_tx_second = rtc_now.second; + peer.last_tx_minute = tx_minute; peer.last_tx_ms = now; const char* recipient = board_id_for_label(peer.label); String message = String(BOARD_ID) + " says Hi to " + recipient + " iter=" + String(peer.tx_iter++);