# Exercise 306: microReticulum BLE file transfer with OLED display
This exercise builds on Exercise 305's equal-peer BLE file transfer and adds the shared `lib/tbeam_display` OLED service. Both boards run the same dual-role BLE interface, form a Reticulum Link, and then send the selected text file across that Link at the same time.
The OLED display is intentionally plain: incoming `FTD` file data is rendered as scrolling text only. File begin/end metadata, checksums, link state, and debug records remain on the serial monitor but are not shown on the OLED.
The file transfer protocol is intentionally small and visible on the serial console:
```text
FTB -> file begin, with file name, byte count, chunk count, and checksum
FTD -> numbered file data chunk
FTE -> file end, with verification metadata repeated
```
Each receiver checks byte count, chunk count, and FNV-1a checksum. After a sender completes a transfer, it rests for 10 seconds and then starts the same selected file again.
## Sample Set
Exercise 306 uses the same payload files as the Pi Zero BLE Reticulum tests:
The selected file is compiled into the firmware. The transfer code does not care which file is selected; `platformio.ini` chooses the source text through `custom_text_source`, and `scripts/embed_text.py` generates `SelectedText.h` in the build directory before compilation.
## Transfer Profiles
The transfer pressure is selected in `platformio.ini` with build flags:
```ini
-D FILE_TRANSFER_CHUNK_SIZE=32
-D FILE_TRANSFER_CHUNK_INTERVAL_MS=500
```
`FILE_TRANSFER_CHUNK_SIZE` is the number of text bytes placed in each application-level `FTD` message before microReticulum wraps and encrypts it as a Link packet. Larger chunks reduce the number of packets needed for a file, but each encrypted packet becomes larger. If it grows beyond what the ESP32 BLE transport can reliably carry under simultaneous two-way traffic, Reticulum may log Link decrypt/HMAC failures because ciphertext arrived damaged or incomplete.
`FILE_TRANSFER_CHUNK_INTERVAL_MS` is the delay between application-level file chunks. Smaller intervals increase throughput, but also increase BLE write/notify pressure. With both nodes transmitting at the same time, too short a cadence can overflow buffers or expose ordering/loss issues in the current ESP32 BLE transport.
The conservative bring-up profile uses:
```text
32 byte chunks, 500 ms between chunks
```
The Pi-Zero-comparison profile uses:
```text
300 byte chunks, 100 ms between chunks
```
That is the apples-to-apples starting point for the previous Zero-to-Zero tests. Those commands requested `--message-chunk-size 900`, but the Python sender intentionally applied an internal board/Link-budget cap before sending. The run17 report for the Constitution transfer shows effective chunk data around 300 to 316 bytes, not 900 bytes, with roughly 100 ms sender pacing.
`VERIFY_FAIL` means the file protocol received an incomplete or corrupted transfer. A Reticulum Link HMAC/decryption error means corruption happened earlier, before the file protocol could parse the packet.
## Priority
See Exercise 304_microReticulum_ble_dual_role_ping_pong README.md for explanation of "deterministic tie-breaker" of the role of client and server based on the ESP32 MAC.
`jp_native` builds a Linux console program instead of ESP32 firmware. It uses the host Bluetooth adapter through BlueZ D-Bus, skips the OLED path, and prints received text to stdout. The current jp payload is `texts/little_boy_blue.txt`.
`jp_native_peripheral` is the first Linux peripheral/server scaffold. It builds a separate binary that checks for BlueZ `GattManager1` and `LEAdvertisingManager1` support on the host adapter. It does not yet register the full Exercise 306 GATT service or accept a T-Beam connection.
## Building
### ESP32
Build the ESP32/T-Beam firmware with one of the `tbeam_*` environments. Each selected text environment produces one firmware image. Build it once, then upload that same image to both boards.
cd /usr/local/src/microreticulum/microReticulumTbeam
pio run -d exercises/306_microReticulum_ble_file_transfer_oled -e tbeam_if
```
Build the Pi-Zero-profile Constitution sample:
```bash
source /home/jlpoole/rnsenv/bin/activate
cd /usr/local/src/microreticulum/microReticulumTbeam
pio run -d exercises/306_microReticulum_ble_file_transfer_oled -e tbeam_constitution_pi_zero_profile
```
After the build succeeds, upload the same environment to both boards. These commands may be run one after the other:
```bash
pio run -d exercises/306_microReticulum_ble_file_transfer_oled -e tbeam_if -t upload --upload-port /dev/ttytDAN
pio run -d exercises/306_microReticulum_ble_file_transfer_oled -e tbeam_if -t upload --upload-port /dev/ttytBOB
```
Use the same `-e` value in upload commands that you used for the build.
For strict parallel uploads, use `esptool.py` directly against the already-built artifacts. This avoids two concurrent `pio run` processes touching the same `.pio` build directory:
```bash
cd /usr/local/src/microreticulum/microReticulumTbeam/exercises/306_microReticulum_ble_file_transfer_oled
The host binary is a BlueZ BLE central. It expects the T-Beam to advertise the Exercise 306 service, then receives file-transfer text on the console. Because it uses system D-Bus and the Bluetooth adapter, sandboxed runs may require approval.
Build the jp peripheral capability-check binary with:
```bash
source /home/jlpoole/rnsenv/bin/activate
cd /usr/local/src/microreticulum/microReticulumTbeam
pio run -d exercises/306_microReticulum_ble_file_transfer_oled -e jp_native_peripheral
This build is expected to report whether the current BlueZ adapter exposes the GATT server and LE advertising managers needed for true Linux peripheral mode.
### AMD64
AMD64 is the same 64-bit x86 Linux target class as Intel x86_64 for this PlatformIO `native` build. On eos, build the same `jp_native` environment on that machine:
```bash
source /home/jlpoole/rnsenv/bin/activate
cd /usr/local/src/microreticulum/microReticulumTbeam
pio run -d exercises/306_microReticulum_ble_file_transfer_oled -e jp_native
The Pi must have BlueZ, GLib/GIO development headers, and a BLE adapter that supports LE central mode. If the Pi is running a 32-bit OS, the result is a 32-bit ARM binary, not ARM64.
Ten seconds after `TX FILE END`, the same selected file starts again. This rest interval is measured after transfer completion, so large files get the same 10-second pause before the next round.
## Debug Lines
Exercise 305 includes machine-parseable debug records for the role-dependent BLE/Link failure investigation. Each record is one line of `key=value` fields.
```text
RNSLINK Link/announce events, peer hashes, Link ids, and Link object ids.
RNSTX Application plaintext sends and encrypted Reticulum packets handed to BLE.
RNSRX Reassembled BLE packets immediately before Reticulum receives them.
RNSDEC Link encrypt/decrypt attempts and failures from microReticulum Link.cpp.
RNSBLE BLE connect, identity, fragment TX/RX, and packet assembly events.
RNSQUEUE BLE RX queue depth, pushes, pops, drops, and high-water marks.
RNSMEM Heap, largest block, PSRAM, and current task stack high-water mark.
Normal packet logging is rate-limited: first 25 packets, then every 25th packet, then all packets for two seconds after the first failure. Define `RNS_DEBUG_VERBOSE=1` in `platformio.ini` to print every packet fingerprint.
Debug hooks are inserted at these points:
```text
src/TBeamSupremeBleInterface.cpp BLE callback boundary, fragment TX/RX, reassembly, queue, packet handoff.
src/main.cpp board-name mapping, announce/link events, application Link send.