#![no_std]
#[cfg(test)]
#[macro_use]
extern crate std;
pub mod registers;
use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::spi::Transfer;
use embedded_hal::digital::v2::OutputPin;
use core::marker::PhantomData;
use registers::{
DataMode, DioMapping, DioPin, FifoMode, InterPacketRxDelay, Mode, Modulation,
ModulationShaping, ModulationType, PacketConfig, PacketDc, PacketFiltering, PacketFormat,
Registers,
};
const FOSC: f32 = 32_000_000.0;
const FSTEP: f32 = FOSC / 524_288.0;
type Result<T, Ecs, Espi> = core::result::Result<T, Error<Ecs, Espi>>;
#[derive(Debug)]
pub enum Error<Ecs, Espi> {
Cs(Ecs),
Spi(Espi),
Timeout,
AesKeySize,
SyncSize,
}
pub struct Rfm69<T, S, D> {
spi: S,
cs: T,
delay: D,
mode: Mode,
dio: [Option<DioMapping>; 6],
rssi: f32,
}
impl<T, S, D, Ecs, Espi> Rfm69<T, S, D>
where
T: OutputPin<Error = Ecs>,
S: Transfer<u8, Error = Espi>,
D: DelayMs<u8>,
{
pub fn new(spi: S, cs: T, delay: D) -> Self {
Rfm69 {
spi,
cs,
delay,
mode: Mode::Standby,
dio: [None; 6],
rssi: 0.0,
}
}
pub fn read_all_regs(&mut self) -> Result<[u8; 0x4f], Ecs, Espi> {
let mut buffer = [0u8; 0x4f];
self.read_many(Registers::OpMode, &mut buffer)?;
Ok(buffer)
}
pub fn mode(&mut self, mode: Mode) -> Result<(), Ecs, Espi> {
let val = mode as u8;
self.update(Registers::OpMode, |r| (r & 0xe3) | val)?;
self.mode = mode;
self.dio()
}
pub fn modulation(&mut self, modulation: Modulation) -> Result<(), Ecs, Espi> {
self.write(Registers::DataModul, modulation.value())
}
pub fn bit_rate(&mut self, bit_rate: f32) -> Result<(), Ecs, Espi> {
let reg = (FOSC / bit_rate) as u16;
let mut val = reg.to_be_bytes();
self.write_many(Registers::BitrateMsb, &mut val)
}
pub fn fdev(&mut self, fdev: f32) -> Result<(), Ecs, Espi> {
let reg = (fdev / FSTEP) as u16;
let mut val = reg.to_be_bytes();
self.write_many(Registers::FdevMsb, &mut val)
}
pub fn frequency(&mut self, frequency: f32) -> Result<(), Ecs, Espi> {
let reg = (frequency / FSTEP) as u32;
let mut val = reg.to_be_bytes();
self.write_many(Registers::FrfMsb, &mut val[1..])
}
pub fn dio_mapping(&mut self, mapping: DioMapping) -> Result<(), Ecs, Espi> {
let pin = mapping.pin;
let dio = Some(mapping);
match pin {
DioPin::Dio0 => self.dio[0] = dio,
DioPin::Dio1 => self.dio[1] = dio,
DioPin::Dio2 => self.dio[2] = dio,
DioPin::Dio3 => self.dio[3] = dio,
DioPin::Dio4 => self.dio[4] = dio,
DioPin::Dio5 => self.dio[5] = dio,
}
self.dio()
}
pub fn clear_dio(&mut self, pin: DioPin) -> Result<(), Ecs, Espi> {
match pin {
DioPin::Dio0 => self.dio[0] = None,
DioPin::Dio1 => self.dio[1] = None,
DioPin::Dio2 => self.dio[2] = None,
DioPin::Dio3 => self.dio[3] = None,
DioPin::Dio4 => self.dio[4] = None,
DioPin::Dio5 => self.dio[5] = None,
}
self.dio()
}
pub fn preamble(&mut self, reg: u16) -> Result<(), Ecs, Espi> {
let mut val = reg.to_be_bytes();
self.write_many(Registers::PreambleMsb, &mut val)
}
pub fn sync(&mut self, sync: &mut [u8]) -> Result<(), Ecs, Espi> {
let len = sync.len();
if len == 0 {
return self.update(Registers::SyncConfig, |r| r & 0x7f);
} else if len > 8 {
Err(Error::SyncSize)?;
}
let reg = 0x80 | ((len - 1) as u8) << 3;
self.write(Registers::SyncConfig, reg)?;
self.write_many(Registers::SyncValue1, sync)
}
pub fn packet(&mut self, packet_config: PacketConfig) -> Result<(), Ecs, Espi> {
let len: u8;
let mut reg = 0x00;
match packet_config.format {
PacketFormat::Fixed(size) => len = size,
PacketFormat::Variable(size) => {
len = size;
reg |= 0x80;
}
}
reg |=
packet_config.dc as u8 | packet_config.filtering as u8 | (packet_config.crc as u8) << 4;
let mut val = [reg, len];
self.write_many(Registers::PacketConfig1, &mut val)?;
reg = packet_config.interpacket_rx_delay as u8 | (packet_config.auto_rx_restart as u8) << 1;
self.update(Registers::PacketConfig2, |r| r & 0x0d | reg)
}
pub fn node_address(&mut self, a: u8) -> Result<(), Ecs, Espi> {
self.write(Registers::NodeAddrs, a)
}
pub fn broadcast_address(&mut self, a: u8) -> Result<(), Ecs, Espi> {
self.write(Registers::BroadcastAddrs, a)
}
pub fn fifo_mode(&mut self, mode: FifoMode) -> Result<(), Ecs, Espi> {
match mode {
FifoMode::NotEmpty => self.update(Registers::FifoThresh, |r| r | 0x80),
FifoMode::Level(level) => self.write(Registers::FifoThresh, level & 0x7f),
}
}
pub fn aes(&mut self, key: &mut [u8]) -> Result<(), Ecs, Espi> {
let len = key.len();
if len == 0 {
return self.update(Registers::PacketConfig2, |r| r & 0xfe);
} else if len == 16 {
self.update(Registers::PacketConfig2, |r| r | 0x01)?;
return self.write_many(Registers::AesKey1, key);
}
Err(Error::AesKeySize)
}
pub fn rssi(&self) -> f32 {
self.rssi
}
pub fn recv(&mut self, buffer: &mut [u8]) -> Result<(), Ecs, Espi> {
if buffer.is_empty() {
return Ok(());
}
self.mode(Mode::Receiver)?;
self.wait_mode_ready()?;
while !self.is_packet_ready()? {}
self.mode(Mode::Standby)?;
self.read_many(Registers::Fifo, buffer)?;
self.rssi = self.read(Registers::RssiValue)? as f32 / -2.0;
Ok(())
}
pub fn send(&mut self, buffer: &mut [u8]) -> Result<(), Ecs, Espi> {
if buffer.is_empty() {
return Ok(());
}
self.mode(Mode::Standby)?;
self.wait_mode_ready()?;
self.reset_fifo()?;
self.write_many(Registers::Fifo, buffer)?;
self.mode(Mode::Transmitter)?;
self.wait_packet_sent()?;
self.mode(Mode::Standby)
}
pub fn is_packet_ready(&mut self) -> Result<bool, Ecs, Espi> {
Ok(self.read(Registers::IrqFlags2)? & 0x04 != 0)
}
fn dio(&mut self) -> Result<(), Ecs, Espi> {
let mut reg = 0x07;
for opt_mapping in self.dio.iter() {
if let Some(mapping) = opt_mapping {
if mapping.dio_mode.eq(self.mode) {
reg |= (mapping.dio_type as u16) << (mapping.pin as u16);
}
}
}
let mut val = reg.to_be_bytes();
self.write_many(Registers::DioMapping1, &mut val)
}
fn reset_fifo(&mut self) -> Result<(), Ecs, Espi> {
self.write(Registers::IrqFlags2, 0x10)
}
fn wait_mode_ready(&mut self) -> Result<(), Ecs, Espi> {
self.with_timeout(100, 5, |rfm| {
Ok((rfm.read(Registers::IrqFlags1)? & 0x80) != 0)
})
}
fn wait_packet_sent(&mut self) -> Result<(), Ecs, Espi> {
self.with_timeout(100, 5, |rfm| {
Ok((rfm.read(Registers::IrqFlags2)? & 0x08) != 0)
})
}
fn with_timeout<F>(&mut self, timeout: u8, step: u8, func: F) -> Result<(), Ecs, Espi>
where
F: Fn(&mut Rfm69<T, S, D>) -> Result<bool, Ecs, Espi>,
{
let mut done = func(self)?;
let mut count = 0;
while !done && count < timeout {
self.delay.delay_ms(step);
count += step;
done = func(self)?;
}
if !done {
Err(Error::Timeout)?;
}
Ok(())
}
fn update<F>(&mut self, reg: Registers, f: F) -> Result<(), Ecs, Espi>
where
F: FnOnce(u8) -> u8,
{
let val = self.read(reg)?;
self.write(reg, f(val))
}
fn write(&mut self, reg: Registers, val: u8) -> Result<(), Ecs, Espi> {
self.write_many(reg, &mut [val])
}
fn write_many(&mut self, reg: Registers, data: &mut [u8]) -> Result<(), Ecs, Espi> {
let mut guard = CsGuard::new(&mut self.cs);
guard.select()?;
self.spi.transfer(&mut [reg.write()]).map_err(Error::Spi)?;
self.spi.transfer(data).map_err(Error::Spi)?;
Ok(())
}
fn read(&mut self, reg: Registers) -> Result<u8, Ecs, Espi> {
let mut buffer = [0u8; 1];
self.read_many(reg, &mut buffer)?;
Ok(buffer[0])
}
fn read_many(&mut self, reg: Registers, buffer: &mut [u8]) -> Result<(), Ecs, Espi> {
let mut guard = CsGuard::new(&mut self.cs);
guard.select()?;
self.spi.transfer(&mut [reg.read()]).map_err(Error::Spi)?;
self.spi.transfer(buffer).map_err(Error::Spi)?;
Ok(())
}
}
struct CsGuard<'a, T, Ecs, Espi>
where
T: OutputPin<Error = Ecs>,
{
cs: &'a mut T,
_phantom: PhantomData<Espi>,
}
impl<'a, T, Ecs, Espi> CsGuard<'a, T, Ecs, Espi>
where
T: OutputPin<Error = Ecs>,
{
fn new(pin: &'a mut T) -> Self {
CsGuard {
cs: pin,
_phantom: PhantomData,
}
}
fn select(&mut self) -> Result<(), Ecs, Espi> {
self.cs.set_low().map_err(Error::Cs)
}
fn unselect(&mut self) -> Result<(), Ecs, Espi> {
self.cs.set_high().map_err(Error::Cs)
}
}
impl<'a, T, Ecs, Espi> Drop for CsGuard<'a, T, Ecs, Espi>
where
T: OutputPin<Error = Ecs>,
{
fn drop(&mut self) {
if self.unselect().is_err() {
panic!("Cannot clear CS guard");
}
}
}
pub fn low_power_lab_defaults<T, S, D, Ecs, Espi>(
mut rfm: Rfm69<T, S, D>,
network_id: u8,
frequency: f32,
) -> Result<Rfm69<T, S, D>, Ecs, Espi>
where
T: OutputPin<Error = Ecs>,
S: Transfer<u8, Error = Espi>,
D: DelayMs<u8>,
{
rfm.mode(Mode::Standby)?;
rfm.modulation(Modulation {
data_mode: DataMode::Packet,
modulation_type: ModulationType::Fsk,
shaping: ModulationShaping::Shaping00,
})?;
rfm.bit_rate(55_555.0)?;
rfm.frequency(frequency)?;
rfm.fdev(50_000.0)?;
rfm.write(Registers::RxBw, 0x42)?;
rfm.preamble(3)?;
rfm.sync(&mut [0x2d, network_id])?;
rfm.packet(PacketConfig {
format: PacketFormat::Variable(66),
dc: PacketDc::None,
filtering: PacketFiltering::None,
crc: true,
interpacket_rx_delay: InterPacketRxDelay::Delay2Bits,
auto_rx_restart: true,
})?;
rfm.fifo_mode(FifoMode::NotEmpty)?;
Ok(rfm)
}
#[cfg(test)]
mod tests;