Skip to content

chrta/rfm69-async

Repository files navigation

RFM69-Async

RFM69-Async is an async driver for the SubGhz transceiver RFM69.

crates.io page docs.rs page

Examples

Examples are found in the examples/ folder separated by the chip manufacturer they are designed to run on. For example:

  • examples/rp are for the RP2040 chip.

The RP2040 binaries are:

  • blinky — board sanity check; no radio involved.
  • rfm69 — single-task send/receive loop.
  • echo_client and echo_server — paired roles for round-trip testing over two boards: client sends, server echoes back.
  • concurrent_demo — splits send and receive across independent embassy tasks driven by a single radio Runner. Headline feature of the Stack / Runner API: user tasks call stack.send() and stack.recv() concurrently with no manual rx/tx interleaving.

Running examples

  • Install tools to debug/flash the firmware. For example to flash the firmware to the rpi pico via USB:
cargo install elf2uf2-rs
  • Change directory to the sample's base directory. For example:
cd examples/rp
  • Build the example

For example:

cargo build --bin rfm69 --release
  • Put the Pico in BOOTSEL mode

Hold the BOOTSEL button while plugging the USB cable in (or, if it is already plugged in, hold BOOTSEL and tap RESET). The board enumerates as a USB mass-storage device named RPI-RP2.

  • Ensure the RPI-RP2 volume is mounted

elf2uf2-rs -d looks at the mount table to find the Pico, so simply having the device appear in dmesg / lsblk is not enough — it must actually be mounted. On desktops with auto-mount this happens automatically; on minimal setups mount it manually, e.g.:

udisksctl mount -b /dev/sda1     # adjust device per `lsblk`
  • Flash the example

For example:

elf2uf2-rs -d target/thumbv6m-none-eabi/release/rfm69

Observing the output on a connected PC

The bins under examples/rp/ ship two independent log transports. Pick whichever matches your hardware setup:

USB CDC serial (no debug probe required)

The default. After the Pico finishes booting it enumerates a second time as a USB CDC ACM device (/dev/ttyACM* on Linux, /dev/tty.usbmodem* on macOS, COM* on Windows) driven by embassy-usb-logger. All log::* output from the example bins and from the driver crate is forwarded over this serial link. Read it with any terminal:

# Linux
screen /dev/ttyACM0 115200          # exit with Ctrl-A Ctrl-\
# or
picocom -b 115200 /dev/ttyACM0

The first line you should see after a freshly flashed echo_server is --- Staring echo server ---, followed by Reading version register... / Version: 0x24 from the driver. Note that the bins wait a few seconds at boot so the host has time to finish enumerating the USB device before logging starts.

This transport carries the driver's logs because the examples crate enables the driver's log cargo feature. If you depend on rfm69-async in your own project and want the same behaviour, enable the log feature on the driver dependency:

rfm69-async = { version = "", features = ["embassy", "log"] }

defmt-rtt over an SWD debug probe (optional)

The bins also pull in defmt-rtt and panic-probe. If you have a debug probe wired to the Pico's SWD pins (e.g. the Raspberry Pi Debug Probe, or a second Pico flashed with the debugprobe firmware), you can flash and stream defmt-formatted output directly with probe-rs instead of UF2:

cargo install probe-rs-tools
probe-rs run --chip RP2040 target/thumbv6m-none-eabi/release/rfm69

probe-rs run halts the target on a panic and prints the decoded panic message; UF2 flashing has no equivalent. To also forward driver-internal logs through this transport, additionally enable the driver's defmt feature (already on in the examples).

HIL (hardware-in-the-loop) testing

A two-board automated round-trip test lives in hil-runner/ (host-side assertion engine) plus examples/rp/src/bin/hil_send_client.rs + hil_recv_server.rs (the test bins). The pipeline — build, picotool-flash both boards, stream their USB-CDC log output, assert each side passes its scenario — is driven by just.

Prerequisites:

  • Two RP2040 boards wired identically to the rest of examples/rp/ and USB-connected to the host.
  • picotool — install from upstream: https://github.com/raspberrypi/picotool
  • justcargo install just.

Discover each board's picotool serial:

just hil-detect

Create a local .env at the repo root (gitignored) with four entries copied from the output of just hil-detect plus ls /dev/serial/by-id/ after flashing once manually:

HIL_BOARD_A=E660C0D1B3818C32           # client board
HIL_BOARD_B=E660C0D1B381AB12           # server board
HIL_PORT_A=/dev/serial/by-id/usb-...
HIL_PORT_B=/dev/serial/by-id/usb-...

Then:

just hil-test

flashes both boards in the right order, then asserts that hil_send_client emits HIL: PASS sent=100 ack_timeouts=0 and hil_recv_server emits HIL: PASS received=100 within 60 s. Exit codes: 0 = success, 1 = explicit HIL: FAIL on a board, 2 = timeout.

The test exercises the real RF/SPI/ACK round-trip — the bins use the same config::my_defaults profile and Stack/Runner setup as the rest of the examples, with an added 16-bit counter payload so the server can dedup ACK-loss-driven retransmits.

Changelog

User-visible changes are tracked in rfm69-async/CHANGELOG.md, following the Keep a Changelog format.

Releasing

Version bumps are driven by cargo-release; configuration lives in rfm69-async/release.toml. Edit the ## [Unreleased] section of the changelog with the user-facing notes for the new release, then:

cargo install cargo-release          # one-time
cd rfm69-async
cargo release 0.1.0                  # dry-run preview
cargo release 0.1.0 --execute        # bump Cargo.toml + examples path-dep,
                                     # rename the changelog heading, commit, tag
git push --follow-tags               # explicit — release.toml has push = false
cargo publish                        # explicit — release.toml has publish = false

Release tags must be annotated. cargo release already creates annotated tags, so the flow above is fine. If you ever tag by hand — e.g. recreating a tag on main after a rebase-merge — use git tag -a vX.Y.Z -m "Release X.Y.Z", never a lightweight git tag vX.Y.Z.

License

This work is licensed under the GNU Affero General Public License v3.0 only (LICENSE or https://www.gnu.org/licenses/agpl-3.0.html).

SPDX-License-Identifier: AGPL-3.0-only

A small number of files in examples/rp/ were copied or adapted from the rp-rs/rp2040-project-template and embassy-rs/embassy projects and remain under their original MIT OR Apache-2.0 licensing; see licenses/THIRD-PARTY-NOTICES.md for details. Each file's effective license is declared in its own SPDX-License-Identifier header.

Versions 0.0.1 and 0.0.2 were released under the dual MIT OR Apache-2.0 license; that licensing remains in effect for those published versions.

Contribution

Any contribution intentionally submitted for inclusion in the work by you shall be licensed under AGPL-3.0-only, without any additional terms or conditions.

Credits

The code is inspired by https://github.com/almusil/rfm69, which was inspired by older https://github.com/lolzballs/rfm69.

About

Async driver for the SubGhz transceiver RFM69

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors