#![no_std]
#[cfg(test)]
#[macro_use]
extern crate std;
use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::OutputPin;
use core::{convert::TryInto, marker::PhantomData};
use crate::registers::{
ContinuousDagc, DataMode, DccCutoff, DioMapping, DioPin, FifoMode, InterPacketRxDelay,
LnaConfig, LnaGain, LnaImpedance, Mode, Modulation, ModulationShaping, ModulationType,
Pa13dBm1, Pa13dBm2, PacketConfig, PacketDc, PacketFiltering, PacketFormat, Registers, RxBw,
RxBwFreq, RxBwFsk, SensitivityBoost,
};
pub mod 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,
BufferTooSmall,
PacketTooLarge,
}
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>,
S: Write<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;
self.write_many(Registers::BitrateMsb, ®.to_be_bytes())
}
pub fn fdev(&mut self, fdev: f32) -> Result<(), Ecs, Espi> {
let reg = (fdev / FSTEP) as u16;
self.write_many(Registers::FdevMsb, ®.to_be_bytes())
}
pub fn frequency(&mut self, frequency: f32) -> Result<(), Ecs, Espi> {
let reg = (frequency / FSTEP) as u32;
self.write_many(Registers::FrfMsb, ®.to_be_bytes()[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> {
self.write_many(Registers::PreambleMsb, ®.to_be_bytes())
}
pub fn sync(&mut self, sync: &[u8]) -> Result<(), Ecs, Espi> {
let len = sync.len();
if len == 0 {
return self.update(Registers::SyncConfig, |r| r & 0x7f);
} else if len > 8 {
return 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;
self.write_many(Registers::PacketConfig1, &[reg, len])?;
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: &[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 recv_large(&mut self, buffer: &mut [u8]) -> Result<usize, Ecs, Espi> {
self.mode(Mode::Receiver)?;
while self.is_fifo_empty()? {}
let len: usize = self.read(Registers::Fifo)?.into();
if len > buffer.len() {
for _ in 0..len {
while self.is_fifo_empty()? {}
self.read(Registers::Fifo)?;
}
self.mode(Mode::Standby)?;
self.rssi = self.read(Registers::RssiValue)? as f32 / -2.0;
return Err(Error::BufferTooSmall);
}
for b in &mut buffer[0..len] {
while self.is_fifo_empty()? {}
*b = self.read(Registers::Fifo)?;
}
self.mode(Mode::Standby)?;
self.rssi = self.read(Registers::RssiValue)? as f32 / -2.0;
Ok(len)
}
pub fn send(&mut self, buffer: &[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 send_large(&mut self, buffer: &[u8]) -> Result<(), Ecs, Espi> {
let packet_size: u8 = buffer.len().try_into().or(Err(Error::PacketTooLarge))?;
self.mode(Mode::Standby)?;
self.wait_mode_ready()?;
self.reset_fifo()?;
self.write(Registers::Fifo, packet_size)?;
self.mode(Mode::Transmitter)?;
for b in buffer {
while self.is_fifo_full()? {}
self.write(Registers::Fifo, *b)?;
}
self.wait_packet_sent()?;
self.mode(Mode::Standby)
}
pub fn is_sync_address_match(&mut self) -> Result<bool, Ecs, Espi> {
Ok(self.read(Registers::IrqFlags1)? & 0x01 != 0)
}
pub fn is_fifo_empty(&mut self) -> Result<bool, Ecs, Espi> {
Ok(self.read(Registers::IrqFlags2)? & 0x40 == 0)
}
pub fn is_fifo_full(&mut self) -> Result<bool, Ecs, Espi> {
Ok(self.read(Registers::IrqFlags2)? & 0x80 != 0)
}
pub fn is_packet_ready(&mut self) -> Result<bool, Ecs, Espi> {
Ok(self.read(Registers::IrqFlags2)? & 0x04 != 0)
}
pub fn lna(&mut self, lna: LnaConfig) -> Result<(), Ecs, Espi> {
let reg = (lna.zin as u8) | (lna.gain_select as u8);
self.update(Registers::Lna, |r| (r & 0x78) | reg)
}
pub fn rssi_threshold(&mut self, threshold: u8) -> Result<(), Ecs, Espi> {
self.write(Registers::RssiThresh, threshold)
}
pub fn sensitivity_boost(&mut self, boost: SensitivityBoost) -> Result<(), Ecs, Espi> {
self.write(Registers::TestLna, boost as u8)
}
pub fn pa13_dbm1(&mut self, pa13: Pa13dBm1) -> Result<(), Ecs, Espi> {
self.write(Registers::TestPa1, pa13 as u8)
}
pub fn pa13_dbm2(&mut self, pa13: Pa13dBm2) -> Result<(), Ecs, Espi> {
self.write(Registers::TestPa2, pa13 as u8)
}
pub fn continuous_dagc(&mut self, cdagc: ContinuousDagc) -> Result<(), Ecs, Espi> {
self.write(Registers::TestDagc, cdagc as u8)
}
pub fn rx_bw<RxBwT>(&mut self, rx_bw: RxBw<RxBwT>) -> Result<(), Ecs, Espi>
where
RxBwT: RxBwFreq,
{
self.write(
Registers::RxBw,
rx_bw.dcc_cutoff as u8 | rx_bw.rx_bw.value(),
)
}
pub fn rx_afc_bw<RxBwT>(&mut self, rx_bw: RxBw<RxBwT>) -> Result<(), Ecs, Espi>
where
RxBwT: RxBwFreq,
{
self.write(
Registers::AfcBw,
rx_bw.dcc_cutoff as u8 | rx_bw.rx_bw.value(),
)
}
pub fn write(&mut self, reg: Registers, val: u8) -> Result<(), Ecs, Espi> {
self.write_many(reg, &[val])
}
pub fn write_many(&mut self, reg: Registers, data: &[u8]) -> Result<(), Ecs, Espi> {
let mut guard = CsGuard::new(&mut self.cs);
guard.select()?;
self.spi.write(&[reg.write()]).map_err(Error::Spi)?;
self.spi.write(data).map_err(Error::Spi)?;
Ok(())
}
pub fn read(&mut self, reg: Registers) -> Result<u8, Ecs, Espi> {
let mut buffer = [0u8; 1];
self.read_many(reg, &mut buffer)?;
Ok(buffer[0])
}
pub 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.write(&[reg.read()]).map_err(Error::Spi)?;
self.spi.transfer(buffer).map_err(Error::Spi)?;
Ok(())
}
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);
}
}
}
self.write_many(Registers::DioMapping1, ®.to_be_bytes())
}
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 {
return 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))
}
}
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>,
S: Write<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.rx_bw(RxBw {
dcc_cutoff: DccCutoff::Percent4,
rx_bw: RxBwFsk::Khz125dot0,
})?;
rfm.preamble(3)?;
rfm.sync(&[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)?;
rfm.lna(LnaConfig {
zin: LnaImpedance::Ohm50,
gain_select: LnaGain::AgcLoop,
})?;
rfm.rssi_threshold(220)?;
rfm.continuous_dagc(ContinuousDagc::ImprovedMarginAfcLowBetaOn0)?;
Ok(rfm)
}
#[cfg(test)]
mod tests;