embedded_nrf24l01/
lib.rs

1// Copyright 2018, Astro <astro@spaceboyz.net>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE>. This file
4// may not be copied, modified, or distributed except according to
5// those terms.
6
7//! nRF24L01+ driver for use with [embedded-hal](https://crates.io/crates/embedded-hal)
8
9#![warn(missing_docs, unused)]
10
11
12#![no_std]
13#[macro_use]
14extern crate bitfield;
15
16use core::fmt;
17use core::fmt::Debug;
18use embedded_hal::blocking::spi::Transfer as SpiTransfer;
19use embedded_hal::digital::v2::OutputPin;
20
21mod config;
22pub use crate::config::{Configuration, CrcMode, DataRate};
23pub mod setup;
24
25mod registers;
26use crate::registers::{Config, Register, SetupAw, Status};
27mod command;
28use crate::command::{Command, ReadRegister, WriteRegister};
29mod payload;
30pub use crate::payload::Payload;
31mod error;
32pub use crate::error::Error;
33
34mod device;
35pub use crate::device::Device;
36mod standby;
37pub use crate::standby::StandbyMode;
38mod rx;
39pub use crate::rx::RxMode;
40mod tx;
41pub use crate::tx::TxMode;
42
43/// Number of RX pipes with configurable addresses
44pub const PIPES_COUNT: usize = 6;
45/// Minimum address length
46pub const MIN_ADDR_BYTES: usize = 3;
47/// Maximum address length
48pub const MAX_ADDR_BYTES: usize = 5;
49
50/// Driver for the nRF24L01+
51///
52/// Never deal with this directly. Instead, you store one of the following types:
53///
54/// * [`StandbyMode<D>`](struct.StandbyMode.html)
55/// * [`RxMode<D>`](struct.RxMode.html)
56/// * [`TxMode<D>`](struct.TxMode.html)
57///
58/// where `D: `[`Device`](trait.Device.html)
59pub struct NRF24L01<E: Debug, CE: OutputPin<Error = E>, CSN: OutputPin<Error = E>, SPI: SpiTransfer<u8>> {
60    ce: CE,
61    csn: CSN,
62    spi: SPI,
63    config: Config,
64}
65
66impl<E: Debug, CE: OutputPin<Error = E>, CSN: OutputPin<Error = E>, SPI: SpiTransfer<u8, Error = SPIE>, SPIE: Debug> fmt::Debug
67    for NRF24L01<E, CE, CSN, SPI>
68{
69    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70        write!(f, "NRF24L01")
71    }
72}
73
74impl<E: Debug, CE: OutputPin<Error = E>, CSN: OutputPin<Error = E>, SPI: SpiTransfer<u8, Error = SPIE>, SPIE: Debug>
75    NRF24L01<E, CE, CSN, SPI>
76{
77    /// Construct a new driver instance.
78    pub fn new(mut ce: CE, mut csn: CSN, spi: SPI) -> Result<StandbyMode<Self>, Error<SPIE>> {
79        ce.set_low().unwrap();
80        csn.set_high().unwrap();
81
82        // Reset value
83        let mut config = Config(0b0000_1000);
84        config.set_mask_rx_dr(false);
85        config.set_mask_tx_ds(false);
86        config.set_mask_max_rt(false);
87        let mut device = NRF24L01 {
88            ce,
89            csn,
90            spi,
91            config,
92        };
93        assert!(device.is_connected().unwrap());
94
95        // TODO: activate features?
96
97        StandbyMode::power_up(device).map_err(|(_, e)| e)
98    }
99
100    /// Reads and validates content of the `SETUP_AW` register.
101    pub fn is_connected(&mut self) -> Result<bool, Error<SPIE>> {
102        let (_, setup_aw) = self.read_register::<SetupAw>()?;
103        let valid = setup_aw.aw() >= 3 && setup_aw.aw() <= 5;
104        Ok(valid)
105    }
106}
107
108impl<E: Debug, CE: OutputPin<Error = E>, CSN: OutputPin<Error = E>, SPI: SpiTransfer<u8, Error = SPIE>, SPIE: Debug> Device
109    for NRF24L01<E, CE, CSN, SPI>
110{
111    type Error = Error<SPIE>;
112
113    fn ce_enable(&mut self) {
114        self.ce.set_high().unwrap();
115    }
116
117    fn ce_disable(&mut self) {
118        self.ce.set_low().unwrap();
119    }
120
121    fn send_command<C: Command>(
122        &mut self,
123        command: &C,
124    ) -> Result<(Status, C::Response), Self::Error> {
125        // Allocate storage
126        let mut buf_storage = [0; 33];
127        let len = command.len();
128        let buf = &mut buf_storage[0..len];
129        // Serialize the command
130        command.encode(buf);
131
132        // SPI transaction
133        self.csn.set_low().unwrap();
134        let transfer_result = self.spi.transfer(buf).map(|_| {});
135        self.csn.set_high().unwrap();
136        // Propagate Err only after csn.set_high():
137        transfer_result?;
138
139        // Parse response
140        let status = Status(buf[0]);
141        let response = C::decode_response(buf);
142
143        Ok((status, response))
144    }
145
146    fn write_register<R: Register>(&mut self, register: R) -> Result<Status, Self::Error> {
147        let (status, ()) = self.send_command(&WriteRegister::new(register))?;
148        Ok(status)
149    }
150
151    fn read_register<R: Register>(&mut self) -> Result<(Status, R), Self::Error> {
152        self.send_command(&ReadRegister::new())
153    }
154
155    fn update_config<F, R>(&mut self, f: F) -> Result<R, Self::Error>
156    where
157        F: FnOnce(&mut Config) -> R,
158    {
159        // Mutate
160        let old_config = self.config.clone();
161        let result = f(&mut self.config);
162
163        if self.config != old_config {
164            let config = self.config.clone();
165            self.write_register(config)?;
166        }
167        Ok(result)
168    }
169}