1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2018, Astro <astro@spaceboyz.net>
//
// Licensed under the Apache License, Version 2.0 <LICENSE>. This file
// may not be copied, modified, or distributed except according to
// those terms.

//! nRF24L01+ driver for use with [embedded-hal](https://crates.io/crates/embedded-hal)

#![warn(missing_docs, unused)]


#![no_std]
extern crate embedded_hal;
#[macro_use]
extern crate bitfield;

use core::fmt;
use core::fmt::Debug;
use embedded_hal::digital::OutputPin;
use embedded_hal::blocking::spi::Transfer as SpiTransfer;

mod config;
pub use config::{Configuration, CrcMode, DataRate};
pub mod setup;

mod registers;
use registers::{Register, Config, Status, SetupAw};
mod command;
use command::{Command, ReadRegister, WriteRegister};
mod payload;
pub use payload::Payload;

mod device;
pub use device::Device;
mod standby;
pub use standby::StandbyMode;
mod rx;
pub use rx::RxMode;
mod tx;
pub use tx::TxMode;

/// Number of RX pipes with configurable addresses
pub const PIPES_COUNT: usize = 6;
/// Minimum address length
pub const MIN_ADDR_BYTES: usize = 3;
/// Maximum address length
pub const MAX_ADDR_BYTES: usize = 5;


/// Driver for the nRF24L01+
///
/// Never deal with this directly. Instead, you store one of the following types:
///
/// * [`StandbyMode<D>`](struct.StandbyMode.html)
/// * [`RxMode<D>`](struct.RxMode.html)
/// * [`TxMode<D>`](struct.TxMode.html)
///
/// where `D: `[`Device`](trait.Device.html)
pub struct NRF24L01<CE: OutputPin, CSN: OutputPin, SPI: SpiTransfer<u8>> {
    ce: CE,
    csn: CSN,
    spi: SPI,
    config: Config,
}

impl<CE: OutputPin, CSN: OutputPin, SPI: SpiTransfer<u8, Error=SPIE>, SPIE: Debug> fmt::Debug for NRF24L01<CE, CSN, SPI> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NRF24L01")
    }
}

impl<CE: OutputPin, CSN: OutputPin, SPI: SpiTransfer<u8, Error=SPIE>, SPIE: Debug> NRF24L01<CE, CSN, SPI> {
    /// Construct a new driver instance.
    pub fn new(mut ce: CE, mut csn: CSN, spi: SPI) -> Result<StandbyMode<Self>, SPIE> {
        ce.set_low();
        csn.set_high();

        // Reset value
        let mut config = Config(0b0000_1000);
        config.set_mask_rx_dr(true);
        config.set_mask_tx_ds(true);
        config.set_mask_max_rt(true);
        let mut device = NRF24L01 {
            ce, csn, spi,
            config,
        };
        assert!(device.is_connected().unwrap());

        // TODO: activate features?
        
        StandbyMode::power_up(device)
            .map_err(|(_, e)| e)
    }

    /// Reads and validates content of the `SETUP_AW` register.
    pub fn is_connected(&mut self) -> Result<bool, SPIE> {
        let (_, setup_aw) =
            self.read_register::<SetupAw>()?;
        let valid =
            setup_aw.aw() >= 3 &&
            setup_aw.aw() <= 5;
        Ok(valid)
    }
}

impl<CE: OutputPin, CSN: OutputPin, SPI: SpiTransfer<u8, Error=SPIE>, SPIE: Debug> Device for NRF24L01<CE, CSN, SPI> {
    type Error = SPIE;

    fn ce_enable(&mut self) {
        self.ce.set_high();
    }

    fn ce_disable(&mut self) {
        self.ce.set_low();
    }

    fn send_command<C: Command>(&mut self, command: &C) -> Result<(Status, C::Response), Self::Error> {
        // Allocate storage
        let mut buf_storage = [0; 33];
        let len = command.len();
        let buf = &mut buf_storage[0..len];
        // Serialize the command
        command.encode(buf);

        // SPI transaction
        self.csn.set_low();
        let transfer_result = self.spi.transfer(buf)
            .map(|_| {});
        self.csn.set_high();
        // Propagate Err only after csn.set_high():
        transfer_result?;

        // Parse response
        let status = Status(buf[0]);
        let response = C::decode_response(buf);

        Ok((status, response))
    }

    fn write_register<R: Register>(&mut self, register: R) -> Result<Status, Self::Error> {
        let (status, ()) = self.send_command(&WriteRegister::new(register))?;
        Ok(status)
    }

    fn read_register<R: Register>(&mut self) -> Result<(Status, R), Self::Error> {
        self.send_command(&ReadRegister::new())
    }

    fn update_config<F, R>(&mut self, f: F) -> Result<R, Self::Error>
        where F: FnOnce(&mut Config) -> R
    {
        // Mutate
        let old_config = self.config.clone();
        let result = f(&mut self.config);

        if self.config != old_config {
            let config = self.config.clone();
            self.write_register(config)?;
        }
        Ok(result)
    }
}