radio_at86rf212/
lib.rs

1//! AT86RF212 Radio Driver
2//! Driver / Core
3//! 
4//! See also: 
5//! - https://github.com/ryankurte/libat86rf212
6//! 
7//! Copyright 2018 Ryan Kurte
8
9#![no_std]
10
11extern crate embedded_hal as hal;
12
13extern crate radio;
14use radio::Registers;
15
16use hal::blocking::{spi, delay};
17use hal::digital::{OutputPin};
18use hal::spi::{Mode, Phase, Polarity};
19
20pub mod device;
21pub use device::{TrxCmd, TrxStatus, CCAMode, defaults};
22pub mod regs;
23pub use regs::{Register};
24
25// At86rf212 error types
26#[derive(Copy, Clone, Debug)]
27pub enum At86rf212Error<SPIError> {
28    /// Communication error
29    SPI(SPIError),
30    /// Invalid part error 
31    InvalidPart(u8),
32    /// Length error (mismatch or length exceeds allowable)
33    InvalidLength(usize),
34    /// Command failed after MAX_RETRIES
35    MaxRetries,
36    /// PLL locking error
37    PLLLock,
38    /// Digital voltage error
39    DigitalVoltage,
40    /// Analogue voltage error
41    AnalogueVoltage,
42}
43
44impl <SPIError>From<SPIError> for At86rf212Error<SPIError> {
45	fn from(e: SPIError) -> At86rf212Error<SPIError> {
46		At86rf212Error::SPI(e)
47	}
48}
49
50/// AT86RF212 SPI operating mode
51pub const MODE: Mode = Mode {
52    polarity: Polarity::IdleLow,
53    phase: Phase::CaptureOnFirstTransition,
54};
55
56/// AT86RF212 device object
57pub struct At86Rf212<SPI, OUTPUT, DELAY> {
58    spi: SPI,
59    reset: OUTPUT,
60    cs: OUTPUT,
61    sleep: OUTPUT,
62    delay: DELAY,
63    auto_crc: bool,
64}
65
66impl<E, SPI, OUTPUT, DELAY> At86Rf212<SPI, OUTPUT, DELAY>
67where
68    SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
69    OUTPUT: OutputPin,
70    DELAY: delay::DelayMs<u32>,
71{
72    pub fn new(spi: SPI, reset: OUTPUT, cs: OUTPUT, sleep: OUTPUT, delay: DELAY) -> Result<Self, At86rf212Error<E>> {
73        let mut at86rf212 = At86Rf212 { spi, reset, cs, sleep, delay, auto_crc: true };
74
75        // Disable slee mode
76        at86rf212.sleep.set_low();
77
78        // Reset pulse
79        at86rf212.reset.set_low();
80        at86rf212.delay.delay_ms(10);
81        at86rf212.reset.set_high();
82        
83        // Wait for init
84        at86rf212.delay.delay_ms(20);
85
86        // Check communication
87        let who = at86rf212.reg_read(Register::PART_NUM)?;
88        if who != 0x07 {
89            return Err(At86rf212Error::InvalidPart(who));
90        }
91
92        // Disable TRX
93        at86rf212.set_state(TrxCmd::TRX_OFF)?;
94
95        // Check digital voltage is ok
96        let v = at86rf212.reg_read(Register::VREG_CTRL)?;
97        if v & regs::VREG_CTRL_DVDD_OK_MASK == 0 {
98            return Err(At86rf212Error::DigitalVoltage);
99        }
100
101        // Set default channel
102        at86rf212.set_channel(defaults::CHANNEL)?;
103
104        // Set default CCA mode
105        at86rf212.set_cca_mode(defaults::CCA_MODE)?;
106
107        // Enable CSMA-CA
108        // Set binary exponentials
109        at86rf212.reg_write(Register::CSMA_BE, (defaults::MINBE << regs::CSMA_BE_MIN_SHIFT) | ((defaults::MAXBE as u8) << regs::CSMA_BE_MAX_SHIFT))?;
110
111        // Set max CMSA retries
112        at86rf212.reg_update(Register::XAH_CTRL_0, regs::XAH_CTRL_MAX_CSMA_RETRIES_MASK, defaults::MAX_CSMA_BACKOFFS << regs::XAH_CTRL_MAX_CSMA_RETRIES_SHIFT)?;
113
114        // Enable promiscuous mode auto ack
115        at86rf212.reg_update(Register::XAH_CTRL_1, regs::XAH_CTRL_1_AACK_PROM_MODE_MASK, 1 << regs::XAH_CTRL_1_AACK_PROM_MODE_SHIFT)?;
116
117        // Enable auto-crc for transmit mode
118        at86rf212.reg_update(Register::TRX_CTRL_1, regs::TRX_CTRL1_TX_AUTO_CRC_ON_MASK, 1 << regs::TRX_CTRL1_TX_AUTO_CRC_ON_SHIFT)?;
119
120        // Enable IRQ_MASK so enabled interrupt cause IRQ to be asserted
121        at86rf212.reg_update(Register::TRX_CTRL_1, regs::TRX_CTRL1_IRQ_MASK_MODE_MASK, 1 << regs::TRX_CTRL1_IRQ_MASK_MODE_SHIFT)?;
122
123        // Enable dynamic frame buffer protection
124        at86rf212.reg_update(Register::TRX_CTRL_2, regs::TRX_CTRL2_RX_SAFE_MODE_MASK, 1 << regs::TRX_CTRL2_RX_SAFE_MODE_SHIFT)?;
125
126        // TODO: Enable desired interrupts
127
128        Ok(at86rf212)
129    }
130
131    /// Read a frame from the device
132    pub fn read_frame<'a>(&mut self, data: &'a mut [u8]) -> Result<&'a [u8], At86rf212Error<E>> {
133        // Setup read frame command
134        let cmd: [u8; 1] = [device::FRAME_READ_FLAG as u8];
135        // Assert CS
136        self.cs.set_low();
137        // Write command
138        match self.spi.write(&cmd) {
139            Ok(_r) => (),
140            Err(e) => {
141                self.cs.set_high();
142                return Err(At86rf212Error::SPI(e));
143            }
144        };
145        // Transfer data
146        let res = match self.spi.transfer(data) {
147            Ok(r) => r,
148            Err(e) => {
149                self.cs.set_high();
150                return Err(At86rf212Error::SPI(e));
151            }
152        };
153        // Clear CS
154        self.cs.set_high();
155        // Return result (contains returned data)
156        Ok(res)
157    }
158
159    /// Write a frame to the device
160    pub fn write_frame(&mut self, data: &[u8]) -> Result<(), At86rf212Error<E>> {
161        // Setup write frame command
162        let mut cmd: [u8; 2] = [device::FRAME_WRITE_FLAG as u8, 0];
163        if self.auto_crc {
164            cmd[1] = (data.len() + device::LEN_FIELD_LEN + device::CRC_LEN) as u8;
165        } else {
166            cmd[1] = (data.len() + device::LEN_FIELD_LEN) as u8;
167        }
168        // Assert CS
169        self.cs.set_low();
170        // Write command
171        match self.spi.write(&cmd) {
172            Ok(_r) => (),
173            Err(e) => {
174                self.cs.set_high();
175                return Err(At86rf212Error::SPI(e));
176            }
177        };
178        // Transfer data
179        match self.spi.write(&data) {
180            Ok(_r) => (),
181            Err(e) => {
182                self.cs.set_high();
183                return Err(At86rf212Error::SPI(e));
184            }
185        };
186        // Add CRC padding if required
187        if self.auto_crc {
188            let crc = [0u8; device::CRC_LEN];
189            match self.spi.write(&crc) {
190                Ok(_r) => (),
191                Err(e) => {
192                    self.cs.set_high();
193                    return Err(At86rf212Error::SPI(e));
194                }
195            };
196        }
197        // Clear CS
198        self.cs.set_high();
199
200        Ok(())
201    }
202
203    /// Set the radio state
204    pub fn set_state(&mut self, state: device::TrxCmd) -> Result<(), At86rf212Error<E>> {
205        self.reg_update(Register::TRX_STATE, regs::TRX_STATE_TRX_CMD_MASK, state as u8)
206    }
207
208    pub fn set_state_blocking(&mut self, state: device::TrxCmd) -> Result<(), At86rf212Error<E>> {
209        self.reg_update(Register::TRX_STATE, regs::TRX_STATE_TRX_CMD_MASK, state as u8)?;
210
211        for _i in 0..defaults::MAX_SPI_RETRIES {
212            let v = self.reg_read(Register::TRX_STATE)?;
213            if (v & regs::TRX_STATUS_TRX_STATUS_MASK) != (TrxStatus::STATE_TRANSITION_IN_PROGRESS as u8) {
214                return Ok(());
215            }
216            self.delay.delay_ms(1);
217        }
218
219        Err(At86rf212Error::MaxRetries)
220    }
221
222    /// Fetch the radio state
223    pub fn get_state(&mut self) -> Result<u8, At86rf212Error<E>> {
224        self.reg_read(Register::TRX_STATE).map(|v| v & regs::TRX_STATUS_TRX_STATUS_MASK)
225    }
226
227    /// Set the radio channel
228    pub fn set_channel(&mut self, channel: u8) -> Result<(), At86rf212Error<E>> {
229        self.reg_update(Register::PHY_CC_CCA, regs::PHY_CC_CCA_CHANNEL_MASK, channel << regs::PHY_CC_CCA_CHANNEL_SHIFT)
230    }
231
232    /// Fetch the radio channel
233    pub fn get_channel(&mut self) -> Result<u8, At86rf212Error<E>> {
234        self.reg_read(Register::PHY_CC_CCA).map(|v| (v & regs::PHY_CC_CCA_CHANNEL_MASK) >> regs::PHY_CC_CCA_CHANNEL_SHIFT)
235    }
236
237    /// Set the IRQ mask
238    pub fn set_irq_mask(&mut self, mask: u8) -> Result<(), At86rf212Error<E>> {
239        self.reg_write(Register::IRQ_MASK, mask)
240    }
241
242    /// Fetch the IRQ status (clears pending interrupts)
243    pub fn get_irq_status(&mut self) -> Result<u8, At86rf212Error<E>> {
244        self.reg_read(Register::IRQ_STATUS)
245    }
246
247    /// Set the Clear Channel Assessment (CCA) mode
248    pub fn set_cca_mode(&mut self, mode: CCAMode) -> Result<(), At86rf212Error<E>> {
249        self.reg_update(Register::PHY_CC_CCA, regs::PHY_CC_CCA_CCA_MODE_MASK, (mode as u8) << regs::PHY_CC_CCA_CCA_MODE_SHIFT)
250    }
251
252    /// Fetch the Clear Channel Assessment (CCA) mode
253    pub fn get_cca_mode(&mut self) -> Result<u8, At86rf212Error<E>> {
254        self.reg_read(Register::PHY_CC_CCA).map(|v| (v & regs::PHY_CC_CCA_CCA_MODE_MASK) >> regs::PHY_CC_CCA_CCA_MODE_SHIFT)
255    }
256
257    /// Set the 802.15.4 short address
258    pub fn set_short_address(&mut self, address: u16) -> Result<(), At86rf212Error<E>> {
259        self.reg_write(Register::SHORT_ADDR_0, (address & 0xFF) as u8)?;
260        self.reg_write(Register::SHORT_ADDR_1, (address >> 8) as u8)?;
261        Ok(())
262    }
263
264    /// Set the 802.15.4 PAN ID
265    pub fn set_pan_id(&mut self, pan_id: u16) -> Result<(), At86rf212Error<E>> {
266        self.reg_write(Register::PAN_ID_0, (pan_id & 0xFF) as u8)?;
267        self.reg_write(Register::PAN_ID_1, (pan_id >> 8) as u8)?;
268        Ok(())
269    }
270
271    // Set transmit power (raw, see datasheet for calculations)
272    pub fn set_power_raw(&mut self, power: u8) -> Result<(), At86rf212Error<E>> {
273        self.reg_update(Register::PHY_TX_PWR, regs::PHY_TX_PWR_TX_PWR_MASK, power << regs::PHY_TX_PWR_TX_PWR_SHIFT)?;
274        Ok(())
275    }
276
277
278    fn enable_pll(&mut self) -> Result<(), At86rf212Error<E>> {
279        // Send PLL on cmd
280        self.set_state_blocking(TrxCmd::PLL_ON)?;
281
282        // Await PLL lock (IRQ)
283        for _i in 0 .. defaults::MAX_SPI_RETRIES {
284            let v = self.get_irq_status()?;
285            if (v & regs::IRQ_STATUS_IRQ_0_PLL_LOCK_MASK) != 0 {
286                return Ok(())
287            }
288        }
289
290        Err(At86rf212Error::PLLLock)
291    }
292
293    fn check_tx_rx(&mut self) -> Result<bool, At86rf212Error<E>> {
294        let v = self.get_irq_status()?;
295        if (v & regs::IRQ_STATUS_IRQ_3_TRX_END_MASK) != 0 {
296            Ok(true)
297        } else {
298            Ok(false)
299        }
300    }
301
302    fn get_rx<'a>(&mut self, data: &'a mut [u8]) -> Result<&'a [u8], At86rf212Error<E>>{
303        // Fetch frame length
304        let mut buf = [0u8; 1];
305        let len = self.read_frame(&mut buf)?[0] as usize;
306        // Check length is valid
307        if len > device::MAX_LENGTH {
308            return Err(At86rf212Error::InvalidLength(len));
309        }
310        // Check length fits in provided data array
311        if (len + device::LEN_FIELD_LEN + device::FRAME_RX_OVERHEAD) > data.len() {
312            return Err(At86rf212Error::InvalidLength(len));
313        }
314        // Read the frame
315        self.read_frame(data)
316    }
317
318}
319
320impl<E, SPI, OUTPUT, DELAY> radio::Registers for At86Rf212<SPI, OUTPUT, DELAY>
321where
322    SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
323    OUTPUT: OutputPin,
324    DELAY: delay::DelayMs<u32>,
325{
326    type Error = At86rf212Error<E>;
327    type Register = Register;
328
329    fn reg_read<'a>(&mut self, reg: Self::Register) -> Result<u8, Self::Error>{
330        // Setup read command
331        let mut buf: [u8; 2] = [device::REG_READ_FLAG as u8 | reg as u8, 0];
332        // Assert CS
333        self.cs.set_low();
334        // Transfer data
335        let res = self.spi.transfer(&mut buf);
336        // Clear CS
337        self.cs.set_high();
338        // Return result
339        match res {
340            Ok(v) => Ok(v[1]),
341            Err(e) => Err(At86rf212Error::SPI(e)),
342        }
343    }
344
345    fn reg_write(&mut self, reg: Self::Register, value: u8) -> Result<(), Self::Error>{
346        // Setup write command
347        let buf: [u8; 2] = [device::REG_WRITE_FLAG as u8 | reg as u8, value];
348        // Assert CS
349        self.cs.set_low();
350        // Write command
351        let res = self.spi.write(&buf);
352        // Clear CS
353        self.cs.set_high();
354        // Return result
355        match res {
356            Ok(_) => Ok(()),
357            Err(e) => Err(At86rf212Error::SPI(e)),
358        }
359    }
360    
361    fn reg_update(&mut self, reg: Self::Register, mask: u8, value: u8) -> Result<(), Self::Error>{
362        let mut data = self.reg_read(reg.clone())?;
363        data &= !mask;
364        data |= mask & value;
365        self.reg_write(reg, data)?;
366        Ok(())
367    }
368
369}
370
371impl<E, SPI, OUTPUT, DELAY> radio::Transmit for At86Rf212<SPI, OUTPUT, DELAY>
372where
373    SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
374    OUTPUT: OutputPin,
375    DELAY: delay::DelayMs<u32>,
376{
377    type Error = At86rf212Error<E>;
378
379    fn start_transmit(&mut self, channel: u16, data: &[u8]) -> Result<(), Self::Error>{
380        // Disable TRX
381        self.set_state_blocking(TrxCmd::TRX_OFF)?;
382        // Clear IRQs
383        self.get_irq_status()?;
384        // Set channel
385        self.set_channel(channel as u8)?;
386        // Enable the PLL
387        self.enable_pll()?;
388        // Write data to buffer
389        self.write_frame(data)?;
390        // Set TX mode
391        self.set_state_blocking(TrxCmd::TX_START)?;
392
393        Ok(())
394    }
395
396    fn check_transmit(&mut self) -> Result<bool, Self::Error>{
397        // TODO: check we're in the TX state
398
399        self.check_tx_rx()
400    }
401}
402
403impl<E, SPI, OUTPUT, DELAY> radio::Receive for At86Rf212<SPI, OUTPUT, DELAY>
404where
405    SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
406    OUTPUT: OutputPin,
407    DELAY: delay::DelayMs<u32>,
408{
409    type Error = At86rf212Error<E>;
410    type Info = ();
411
412    fn start_receive(&mut self, channel: u16) -> Result<(), Self::Error> {
413        // Set to IDLE
414        self.set_state_blocking(TrxCmd::TRX_OFF)?;
415
416        // Set channel
417        self.set_channel(channel as u8)?;
418
419        // Clear interrupts
420        self.get_irq_status()?;
421
422        // Enable PLL
423        self.enable_pll()?;
424
425        // Enable RX
426        self.set_state_blocking(TrxCmd::RX_ON)?;
427
428        Ok(())
429    }
430
431    fn get_received<'a>(&mut self, buff: &'a mut [u8]) -> Result<Option<(&'a[u8], Self::Info)>, Self::Error> {
432        // TODO: check we're in the RX state
433
434        // Check whether RX has completed
435        if !self.check_tx_rx()? {
436            return Ok(None);
437        }
438        // Fetch RX data
439        let data = self.get_rx(buff)?;
440        
441        // TODO: parse info from data
442
443        Ok(Some((data, ())))
444    }
445}