use core::convert::TryInto; use embedded_hal::blocking::delay::DelayMs; use embedded_hal::digital::v2::OutputPin; use embedded_nrf24l01::{Configuration, CrcMode, DataRate, RxMode, StandbyMode, NRF24L01}; use mkl25z4_hal::time::CopyableMonoTimer; use mkl25z4_hal::NoError; use protocol::{Packet, Report, Value}; use super::pins::{RadioCe, RadioCs, RadioIrq, RadioPins, RadioPwr, RadioSpi}; use super::sensors::BME280Data; const DEVICE_ID: u8 = 0x20; const KEY: [u8; 16] = include!("../../../common/display_key.txt"); pub struct Radio { nrf24: Option>, pwr: RadioPwr, irq: RadioIrq, salt: Option, time: CopyableMonoTimer, } impl Radio { pub fn init(mut pins: RadioPins, time: CopyableMonoTimer) -> Radio { pins.pwr.set_low().ok(); let nrf24 = NRF24L01::new(pins.ce, pins.cs, pins.spi).unwrap(); let nrf24 = nrf24.power_down().unwrap(); pins.pwr.set_high().ok(); Radio { nrf24: Some(nrf24), pwr: pins.pwr, irq: pins.irq, salt: None, time, } } pub fn enable<'a>(&'a mut self) -> EnabledRadio<'a> { // Enable supply voltage. self.pwr.set_low().ok(); self.time.delay_ms(10u8); // Configure the device. let nrf24 = self.nrf24.take().unwrap(); let mut nrf24 = StandbyMode::power_up(nrf24).unwrap(); self.time.delay_ms(2u8); nrf24.set_frequency(0x32).unwrap(); nrf24.set_rf(DataRate::R2Mbps, 3).unwrap(); nrf24.set_crc(Some(CrcMode::OneByte)).unwrap(); nrf24.set_auto_retransmit(250, 1).unwrap(); nrf24.set_auto_ack(&[true; 6]).unwrap(); nrf24 .set_pipes_rx_enable(&[true, true, false, false, false, false]) .unwrap(); nrf24.set_tx_addr(&[0xB3, 0xB3, 0xB3, 0xB3, 0x00]).unwrap(); nrf24 .set_rx_addr(0, &[0xB3, 0xB3, 0xB3, 0xB3, 0x00]) .unwrap(); nrf24 .set_rx_addr(1, &[0xB3, 0xB3, 0xB3, 0xB3, 0x20]) .unwrap(); nrf24.flush_rx().unwrap(); nrf24.flush_tx().unwrap(); nrf24.set_pipes_rx_lengths(&[Some(32); 6]).unwrap(); EnabledRadio { radio: self, nrf24: Some(nrf24), } } } pub struct EnabledRadio<'a> { radio: &'a mut Radio, nrf24: Option>>, } impl<'a> EnabledRadio<'a> { // TODO: Use generic "SensorValues" instead of BME280Data, which includes ambient light // readings pub fn send_sensor_values(&mut self, values: BME280Data) -> bool { if self.radio.salt.is_none() { if !self.fetch_salt() { return false; } } let mut tx = self.nrf24.take().unwrap().tx().unwrap(); while !tx.can_send().unwrap() {} let mut payload = [0u8; 32]; let mut report = Report { count: 3, values: [Value::Invalid; 8], }; report.values[0] = Value::Temperature(values.temperature as i16); report.values[1] = Value::Pressure(values.pressure); report.values[2] = Value::Humidity(values.humidity as u16); let packet = Packet::Report(report); packet.encode_and_encrypt(&KEY, self.radio.salt.unwrap(), &mut payload); tx.send(&payload).unwrap(); // TODO: Check whether the packet arrived. self.nrf24 = Some(tx.standby().unwrap()); true } fn fetch_salt(&mut self) -> bool { // Request a device ID. let mut tx = self.nrf24.take().unwrap().tx().unwrap(); while !tx.can_send().unwrap() {} let mut payload = [0u8; 32]; let packet = Packet::GetSalt; packet.encode_and_encrypt(&KEY, DEVICE_ID as u64, &mut payload); tx.send(&payload).unwrap(); // TODO: Check whether the packet arrived. // Wait for the initial salt. let mut salt_received = false; let mut rx = tx.standby().unwrap().rx().unwrap(); loop { let packet = match self.receive_packet(&mut rx) { None => break, Some(p) => p, }; match packet { Packet::Salt(salt) => { self.radio.salt = Some((salt & 0x7fffffffffffff00) | DEVICE_ID as u64); salt_received = true; break; } _ => continue, } } self.nrf24 = Some(rx.standby()); salt_received } fn receive_packet( &mut self, rx: &mut RxMode>, ) -> Option { // TODO: Timeout. loop { if let Some(_pipe) = rx.can_read().unwrap() { // Receive a packet. // TODO: Check pipe? let payload = rx.read().unwrap(); if payload.len() != 32 { continue; } let mut payload: [u8; 32] = payload[0..32].try_into().unwrap(); let packet = match Packet::decrypt_and_decode(&KEY, &mut payload) { Ok(p) => p, Err(_) => continue, }; return Some(packet); } } } } impl<'a> Drop for EnabledRadio<'a> { fn drop(&mut self) { let nrf24 = self.nrf24.take().unwrap(); // Disable the chip and remove the supply voltage. let nrf24 = nrf24.power_down().unwrap(); self.radio.pwr.set_high().ok(); self.radio.nrf24 = Some(nrf24); } }