diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/README.md b/exercises/306_microReticulum_ble_file_transfer_oled/README.md index bac6e10..f4effb5 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/README.md +++ b/exercises/306_microReticulum_ble_file_transfer_oled/README.md @@ -304,11 +304,20 @@ strip microreticulum_306_rpi_arm64_dual_little_boy_blue microreticulum_306_rpi_a Run one on each Pi. There should be no required start order for the dual-role test, although starting one Pi a few seconds before the other makes the log easier to read. +Production-style run, with frame tracing off: + ```bash ./microreticulum_306_rpi_arm64_dual_little_boy_blue ./microreticulum_306_rpi_arm64_dual_children ``` +Debug run, with per-Reticulum-frame BLE tracing enabled: + +```bash +./microreticulum_306_rpi_arm64_dual_little_boy_blue --ble-frame-log +./microreticulum_306_rpi_arm64_dual_children --ble-frame-log +``` + Dual builds default to `--ble-dual-policy=first-path-wins`. Both BlueZ roles start, but once either central or peripheral establishes the first peer path, the opposite role is stopped. This avoids exposing two simultaneous Reticulum interfaces to the same peer. Temporary policy overrides are available for debugging: @@ -320,7 +329,13 @@ Temporary policy overrides are available for debugging: ./microreticulum_306_rpi_arm64_dual_little_boy_blue --ble-dual-policy=peripheral-only ``` -`both` preserves the earlier Linux dual behavior and may produce Reticulum `Link-associated packet received on unexpected interface` errors if two BLE paths form at the same time. The `central-only` and `peripheral-only` policies are useful when isolating BlueZ adapter behavior without rebuilding split-role binaries. +`both` preserves the earlier Linux dual behavior and may produce Reticulum `Link-associated packet received on unexpected interface` errors if two BLE paths form at the same time. The `central-only` and `peripheral-only` policies are useful when isolating BlueZ adapter behavior without rebuilding split-role binaries. Options can be combined; for example: + +```bash +./microreticulum_306_rpi_arm64_dual_children --ble-dual-policy=first-path-wins --ble-frame-log +``` + +The `BLE-FRAME` debug lines log reassembled Reticulum frame size and routing context, not the application file chunk size and not the BLE MTU. The current file-transfer profile remains 32-byte `FTD` chunks at 500 ms spacing. In the 2026-05-22 16:04 Pi Zero dual test, first-path-wins converged to one active BLE path, no `Link-associated packet received on unexpected interface` errors appeared, and completed receive transfers ended with `status=OK`. You can copy those binaries to another Pi Zero 2W and rename them for clarity if both Pis use the same CPU architecture, OS bitness, and compatible runtime libraries. Check with: diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_downloads.html b/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_downloads.html index 41bec06..56cc3dc 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_downloads.html +++ b/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_downloads.html @@ -61,7 +61,8 @@ Use two different payload binaries for a simple exchange test. Start one on each Pi; no fixed client/server start order is intended for the dual builds. The default BLE policy is first-path-wins, which stops the opposite BlueZ - role after the first peer path is established. + role after the first peer path is established. Add --ble-frame-log only when + collecting diagnostic Reticulum frame traces.

Downloads

diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_install.md b/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_install.md index fc6c226..e1b8ef2 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_install.md +++ b/exercises/306_microReticulum_ble_file_transfer_oled/raspberrypi_install.md @@ -106,7 +106,7 @@ microreticulum_306_rpi_arm64_dual_little_boy_blue microreticulum_306_rpi_arm64_dual_children ``` -Dual binaries default to `--ble-dual-policy=first-path-wins`: both BlueZ roles start, but the first working peer path stops the opposite role. To reproduce the older experimental behavior, run with `--ble-dual-policy=both`. +Dual binaries default to `--ble-dual-policy=first-path-wins`: both BlueZ roles start, but the first working peer path stops the opposite role. Normal runs leave frame tracing off. To reproduce the verbose diagnostic trace, add `--ble-frame-log`. To reproduce the older experimental dual-path behavior, run with `--ble-dual-policy=both`. Example scp command to a new server named "trixie1": ```bash @@ -165,6 +165,7 @@ jlpoole@trixie1:~ $ ./microreticulum_306_rpi_arm64_dual_children Exercise 306 native BLE file transfer console Node=Node-PIZERO2-DUAL BLE dual policy=first-path-wins +BLE frame log=off Selected file=children.txt bytes=1422 chunk=32 interval_ms=500 repeat_rest_ms=10000 [ustore] Initializing PosixFileSystem [ustore] WARNING: FlashFSFileSystem check failed, reformatting! @@ -191,7 +192,7 @@ or: BLE dual policy first-path-wins: central path won peer=/org/bluez/hci0/dev_D8_3A_DD_1D_CF_B5; stopping peripheral role ``` -The native BLE interfaces also emit temporary `BLE-FRAME` lines for Reticulum frame tracing. Those lines include timestamp, node label, BLE role, peer path/address, BlueZ object path, interface pointer, packet length, and the first packet byte. +With `--ble-frame-log`, the native BLE interfaces emit `BLE-FRAME` lines for Reticulum frame tracing. Those lines include timestamp, node label, BLE role, peer path/address, BlueZ object path, interface pointer, packet length, and the first packet byte. When you have a second unit running, your console will show something like: ```bash [Startup stuff] diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.cpp b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.cpp index 975f68a..314f4fa 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.cpp +++ b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.cpp @@ -76,8 +76,10 @@ static void log_reticulum_frame(const char* direction, first); } -HostBluezBleInterface::HostBluezBleInterface(const std::string& node_label, const char* name) - : InterfaceImpl(name), node_label_(node_label) { +HostBluezBleInterface::HostBluezBleInterface(const std::string& node_label, + bool frame_log_enabled, + const char* name) + : InterfaceImpl(name), node_label_(node_label), frame_log_enabled_(frame_log_enabled) { _IN = true; _OUT = true; _bitrate = 1000000; @@ -484,7 +486,9 @@ void HostBluezBleInterface::send_outgoing(const RNS::Bytes& data) { return; } - log_reticulum_frame("tx", node_label_, device_path_, rx_char_path_, this, data); + if (frame_log_enabled_) { + log_reticulum_frame("tx", node_label_, device_path_, rx_char_path_, this, data); + } size_t total = (data.size() + BLE_PAYLOAD_SIZE - 1) / BLE_PAYLOAD_SIZE; if (total == 0 || total > 65535) { @@ -646,7 +650,9 @@ void HostBluezBleInterface::handle_fragment(const uint8_t* data, size_t len) { } void HostBluezBleInterface::enqueue_packet(const RNS::Bytes& packet) { - log_reticulum_frame("rx", node_label_, device_path_, tx_char_path_, this, packet); + if (frame_log_enabled_) { + log_reticulum_frame("rx", node_label_, device_path_, tx_char_path_, this, packet); + } incoming_packets_.push_back(packet); } diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.h b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.h index 2df13f3..e750d6a 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.h +++ b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezBleInterface.h @@ -12,6 +12,7 @@ class HostBluezBleInterface : public RNS::InterfaceImpl { public: explicit HostBluezBleInterface(const std::string& node_label, + bool frame_log_enabled = false, const char* name = "HostBluezBLE"); ~HostBluezBleInterface() override; @@ -77,6 +78,7 @@ private: static constexpr uint64_t SCAN_RETRY_MS = 5000; std::string node_label_; + bool frame_log_enabled_ = false; GDBusConnection* bus_ = nullptr; std::string adapter_path_; std::string device_path_; diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.cpp b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.cpp index 0a97ac6..97b6fcb 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.cpp +++ b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.cpp @@ -139,8 +139,9 @@ static const char* ADVERTISEMENT_XML = ""; HostBluezPeripheralInterface::HostBluezPeripheralInterface(const std::string& node_label, + bool frame_log_enabled, const char* name) - : InterfaceImpl(name), node_label_(node_label) { + : InterfaceImpl(name), node_label_(node_label), frame_log_enabled_(frame_log_enabled) { _IN = true; _OUT = true; _bitrate = 1000000; @@ -410,7 +411,9 @@ void HostBluezPeripheralInterface::send_outgoing(const RNS::Bytes& data) { return; } - log_reticulum_frame("tx", node_label_, peer_path_, TX_PATH, this, data); + if (frame_log_enabled_) { + log_reticulum_frame("tx", node_label_, peer_path_, TX_PATH, this, data); + } size_t total = (data.size() + BLE_PAYLOAD_SIZE - 1) / BLE_PAYLOAD_SIZE; if (total == 0 || total > 65535) { @@ -527,7 +530,9 @@ void HostBluezPeripheralInterface::handle_fragment(const uint8_t* data, size_t l } void HostBluezPeripheralInterface::enqueue_packet(const RNS::Bytes& packet) { - log_reticulum_frame("rx", node_label_, peer_path_, RX_PATH, this, packet); + if (frame_log_enabled_) { + log_reticulum_frame("rx", node_label_, peer_path_, RX_PATH, this, packet); + } incoming_packets_.push_back(packet); } diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.h b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.h index ca123c5..b7038ea 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.h +++ b/exercises/306_microReticulum_ble_file_transfer_oled/src/HostBluezPeripheralInterface.h @@ -12,6 +12,7 @@ class HostBluezPeripheralInterface : public RNS::InterfaceImpl { public: explicit HostBluezPeripheralInterface(const std::string& node_label, + bool frame_log_enabled = false, const char* name = "HostBluezPeripheral"); ~HostBluezPeripheralInterface() override; @@ -90,6 +91,7 @@ private: static constexpr uint64_t REASSEMBLY_TIMEOUT_MS = 30000; std::string node_label_; + bool frame_log_enabled_ = false; GDBusConnection* bus_ = nullptr; std::string adapter_path_; GDBusNodeInfo* object_manager_node_ = nullptr; diff --git a/exercises/306_microReticulum_ble_file_transfer_oled/src/host_jp_main.cpp b/exercises/306_microReticulum_ble_file_transfer_oled/src/host_jp_main.cpp index d4ec181..04c0de2 100644 --- a/exercises/306_microReticulum_ble_file_transfer_oled/src/host_jp_main.cpp +++ b/exercises/306_microReticulum_ble_file_transfer_oled/src/host_jp_main.cpp @@ -86,6 +86,7 @@ static bool have_peer = false; static bool link_active = false; static bool link_attempted = false; static std::string node_label = HOST_NODE_LABEL; +static bool ble_frame_log_enabled = false; static bool running = true; #if defined(HOST_BLE_DUAL) @@ -479,7 +480,7 @@ static void setup_reticulum() { #if defined(HOST_BLE_DUAL) if (ble_dual_policy != BleDualPolicy::PeripheralOnly) { - auto central = std::shared_ptr(new HostBluezBleInterface(node_label)); + auto central = std::shared_ptr(new HostBluezBleInterface(node_label, ble_frame_log_enabled)); ble_central_impl = static_cast(central.get()); RNS::Interface central_interface(central); central_interface.mode(RNS::Type::Interface::MODE_GATEWAY); @@ -489,7 +490,7 @@ static void setup_reticulum() { } if (ble_dual_policy != BleDualPolicy::CentralOnly) { - auto peripheral = std::shared_ptr(new HostBluezPeripheralInterface(node_label)); + auto peripheral = std::shared_ptr(new HostBluezPeripheralInterface(node_label, ble_frame_log_enabled)); ble_peripheral_impl = static_cast(peripheral.get()); RNS::Interface peripheral_interface(peripheral); peripheral_interface.mode(RNS::Type::Interface::MODE_GATEWAY); @@ -498,7 +499,7 @@ static void setup_reticulum() { peripheral_interface.start(); } #else - auto impl = std::shared_ptr(new HostBleInterface(node_label)); + auto impl = std::shared_ptr(new HostBleInterface(node_label, ble_frame_log_enabled)); ble_impl = static_cast(impl.get()); ble_interface = RNS::Interface(impl); ble_interface.mode(RNS::Type::Interface::MODE_GATEWAY); @@ -617,10 +618,13 @@ int main(int argc, char** argv) { std::signal(SIGINT, handle_signal); std::signal(SIGTERM, handle_signal); -#if defined(HOST_BLE_DUAL) static constexpr const char* policy_prefix = "--ble-dual-policy="; for (int i = 1; i < argc; ++i) { - if (std::strncmp(argv[i], policy_prefix, std::strlen(policy_prefix)) == 0) { + if (std::strcmp(argv[i], "--ble-frame-log") == 0) { + ble_frame_log_enabled = true; + } +#if defined(HOST_BLE_DUAL) + else if (std::strncmp(argv[i], policy_prefix, std::strlen(policy_prefix)) == 0) { const char* value = argv[i] + std::strlen(policy_prefix); if (!set_ble_dual_policy(value)) { std::fprintf(stderr, @@ -628,15 +632,13 @@ int main(int argc, char** argv) { value); return 2; } - } else { + } +#endif + else { std::fprintf(stderr, "Unknown option: %s\n", argv[i]); return 2; } } -#else - (void)argc; - (void)argv; -#endif RNS::loglevel(RNS::LOG_NOTICE); std::printf("Exercise 306 native BLE file transfer console\n"); @@ -644,6 +646,7 @@ int main(int argc, char** argv) { #if defined(HOST_BLE_DUAL) std::printf("BLE dual policy=%s\n", ble_dual_policy_name(ble_dual_policy)); #endif + std::printf("BLE frame log=%s\n", ble_frame_log_enabled ? "on" : "off"); std::printf("Selected file=%s bytes=%u chunk=%u interval_ms=%lu repeat_rest_ms=%lu\n", SELECTED_TEXT_NAME, (unsigned)SELECTED_TEXT_SIZE, (unsigned)TRANSFER_CHUNK_SIZE,