#driver #transceiver #wireless #radio #nrf #userspace

nrf24l01

Linux上NRF24L01(+)收发器的纯Rust用户空间驱动程序

2个不稳定版本

使用旧Rust 2015

0.2.0 2017年9月12日
0.1.0 2017年9月3日

嵌入式开发中排名1358

每月下载量38

MIT/Apache

36KB
465

rust-nrf24l01

Version

Linux上NRF24L01(+)收发器的纯Rust用户空间驱动程序。

该驱动程序的目标是提供一个简单、易于使用、无废话的API来驱动NRF24L01(+)收发器。

这不是从其他语言移植过来的,该驱动程序是基于设备规格从头编写的。

目前,该驱动程序仅公开了NRF24L01芯片提供的最可靠的通信方案的API,即增强型Shockburst™:具有可选有效载荷的自动(硬件)数据包确认、动态有效载荷长度和长CRC(2字节)。

代码已在Raspberry Pi上成功测试。它应该可以在由rust-spidevrust-sysfs-gpio支持的任何平台上运行。

使用方法

nrf24l01作为依赖项添加到您的Cargo.toml

[dependencies]
nrf24l01 = "0.2.0"

示例

简单发射器

extern crate nrf24l01;

use std::time::Duration;
use std::thread::sleep;

use nrf24l01::{TXConfig, NRF24L01, PALevel, OperatingMode};

fn main() {
    let config = TXConfig {
        channel: 108,
        pa_level: PALevel::Low,
        pipe0_address: *b"abcde",
        max_retries: 3,
        retry_delay: 2,
        ..Default::default()
    };

    let mut device = NRF24L01::new(25, 0).unwrap();
    let message = b"sendtest";
    device.configure(&OperatingMode::TX(config)).unwrap();
    device.flush_output().unwrap();

    loop {
        device.push(0, message).unwrap();
        match device.send() {
            Ok(retries) => println!("Message sent, {} retries needed", retries),
            Err(err) => {
                println!("Destination unreachable: {:?}", err);
                device.flush_output().unwrap()
            }
        };
        sleep(Duration::from_millis(5000));
    }
}

简单接收器监听简单发射器

extern crate nrf24l01;

use std::time::Duration;
use std::thread::sleep;

use nrf24l01::{RXConfig, NRF24L01, PALevel, OperatingMode};

fn main() {
    let config = RXConfig {
        channel: 108,
        pa_level: PALevel::Low,
        pipe0_address: *b"abcde",
        ..Default::default()
    };

    let mut device = NRF24L01::new(25, 0).unwrap();
    device.configure(&OperatingMode::RX(config)).unwrap();

    device.listen().unwrap();

    loop {
        sleep(Duration::from_millis(500));
        if device.data_available().unwrap() {
            device
                .read_all(|packet| {
                    println!("Received {:?} bytes", packet.len());
                    println!("Payload {:?}", packet);
                })
                .unwrap();
        }
    }
}

更多示例

交叉编译

rust-cross指南提供了详细和全面的交叉编译说明。

一旦您为ARM等平台设置好环境,就可以像这样轻松交叉编译Raspberry Pi的示例:

cargo build -v --examples --target=arm-unknown-linux-gnueabihf

然后,您可以将任何可执行文件移动到您的测试机器上

scp target/arm-unknown-linux-gnueabihf/debug/examples/multiceiver_ack ...

性能

对于与NRF24L01(+)的SPI通信,我们通过rust-spidev库使用Linux标准的SPIDEV内核驱动程序,效率极高。

对于驱动设备的CE引脚,我们使用GPIO。当前标准的Linux方法是使用sysfs-gpio内核驱动程序。为此,我们使用rust-sysfs-gpio

遗憾的是,sysfs-gpio 的速度较慢,而 rust-sysfs-gpio 的速度则更慢。以 Raspberry A+ 为例,每次发送或读取操作都会产生大约 300 µs 的延迟(相比之下,这大约是设备发送 32 字节并接收确认所需的时间)。

如果您需要非常快速的操作并且使用 Raspberry Pi,可以激活 rpi_accel 功能。该功能使用 rppal 来直接访问 Raspberry Pi 上在 /dev/mem/dev/gpiomem 中暴露的 GPIO 寄存器。因此,延迟变得微不足道:在 Raspberry Pi A+ 上仅为 ~130 ns。

要为您的大 crate 启用 rpi_accel 功能(并禁用默认设置),请将 Cargo.toml 中对该库的依赖项替换为

[dependencies.nrf24l01]
version = "0.2.0"
features = ["rpi_accel"]
default-features = false

如果您知道一个在 Beaglebone 上实现如此快速 GPIO 访问的库,请告诉我!

未来

在未来,我想提供

  • 使用 mio 实现的异步操作;
  • 一个基于流的 API,用于快速、“实时”的数据传输,但可能会牺牲数据包丢失。

我刚开始学习 Rust,所以代码可能不是最优的。请随时提交 pull 请求以改进它!

依赖项

~2MB
~39K SLoC