#![no_std]
extern crate embedded_hal as hal;
#[cfg(feature = "std")]
extern crate std;
use core::fmt::{self, Display, Formatter};
use hal::spi::SpiDevice;
#[macro_use]
pub mod lowlevel;
mod rssi;
use lowlevel::convert::*;
use lowlevel::registers::*;
use lowlevel::types::*;
use rssi::rssi_to_dbm;
#[derive(Debug)]
pub enum Error<SpiE> {
RxOverflow,
CrcMismatch,
Spi(SpiE),
}
impl<SpiE> From<SpiE> for Error<SpiE> {
fn from(e: SpiE) -> Self {
Error::Spi(e)
}
}
impl<SpiE: Display> Display for Error<SpiE> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::RxOverflow => write!(f, "RX FIFO buffer overflowed"),
Self::CrcMismatch => write!(f, "CRC mismatch"),
Self::Spi(e) => write!(f, "SPI error: {}", e),
}
}
}
#[cfg(feature = "std")]
impl<SpiE: Display + core::fmt::Debug> std::error::Error for Error<SpiE> {}
pub struct Cc1101<SPI>(lowlevel::Cc1101<SPI>);
impl<SPI, SpiE> Cc1101<SPI>
where
SPI: SpiDevice<u8, Error = SpiE>,
{
pub fn new(spi: SPI) -> Result<Self, Error<SpiE>> {
Ok(Cc1101(lowlevel::Cc1101::new(spi)?))
}
pub fn set_frequency(&mut self, hz: u64) -> Result<(), Error<SpiE>> {
let (freq0, freq1, freq2) = from_frequency(hz);
self.0.write_register(Config::FREQ0, freq0)?;
self.0.write_register(Config::FREQ1, freq1)?;
self.0.write_register(Config::FREQ2, freq2)?;
Ok(())
}
pub fn set_synthesizer_if(&mut self, hz: u64) -> Result<(), Error<SpiE>> {
self.0
.write_register(Config::FSCTRL1, FSCTRL1::default().freq_if(from_freq_if(hz)).bits())?;
Ok(())
}
pub fn set_agc_target(&mut self, target: TargetAmplitude) -> Result<(), Error<SpiE>> {
self.0.modify_register(Config::AGCCTRL2, |r| {
AGCCTRL2(r).modify().magn_target(target.into()).bits()
})?;
Ok(())
}
pub fn set_agc_filter_length(
&mut self,
filter_length: FilterLength,
) -> Result<(), Error<SpiE>> {
self.0.modify_register(Config::AGCCTRL0, |r| {
AGCCTRL0(r).modify().filter_length(filter_length.into()).bits()
})?;
Ok(())
}
pub fn set_autocalibration(&mut self, autocal: AutoCalibration) -> Result<(), Error<SpiE>> {
self.0.modify_register(Config::MCSM0, |r| {
MCSM0(r).modify().fs_autocal(autocal.into()).bits()
})?;
Ok(())
}
pub fn set_deviation(&mut self, deviation: u64) -> Result<(), Error<SpiE>> {
let (mantissa, exponent) = from_deviation(deviation);
self.0.write_register(
Config::DEVIATN,
DEVIATN::default().deviation_m(mantissa).deviation_e(exponent).bits(),
)?;
Ok(())
}
pub fn set_data_rate(&mut self, baud: u64) -> Result<(), Error<SpiE>> {
let (mantissa, exponent) = from_drate(baud);
self.0
.modify_register(Config::MDMCFG4, |r| MDMCFG4(r).modify().drate_e(exponent).bits())?;
self.0.write_register(Config::MDMCFG3, MDMCFG3::default().drate_m(mantissa).bits())?;
Ok(())
}
pub fn set_chanbw(&mut self, bandwidth: u64) -> Result<(), Error<SpiE>> {
let (mantissa, exponent) = from_chanbw(bandwidth);
self.0.modify_register(Config::MDMCFG4, |r| {
MDMCFG4(r).modify().chanbw_m(mantissa).chanbw_e(exponent).bits()
})?;
Ok(())
}
pub fn get_hw_info(&mut self) -> Result<(u8, u8), Error<SpiE>> {
let partnum = self.0.read_register(Status::PARTNUM)?;
let version = self.0.read_register(Status::VERSION)?;
Ok((partnum, version))
}
pub fn get_rssi_dbm(&mut self) -> Result<i16, Error<SpiE>> {
Ok(rssi_to_dbm(self.0.read_register(Status::RSSI)?))
}
pub fn get_lqi(&mut self) -> Result<u8, Error<SpiE>> {
let lqi = self.0.read_register(Status::LQI)?;
Ok(lqi & !(1u8 << 7))
}
pub fn set_sync_mode(&mut self, sync_mode: SyncMode) -> Result<(), Error<SpiE>> {
let reset: u16 = (SYNC1::default().bits() as u16) << 8 | (SYNC0::default().bits() as u16);
let (mode, word) = match sync_mode {
SyncMode::Disabled => (SyncCheck::DISABLED, reset),
SyncMode::MatchPartial(word) => (SyncCheck::CHECK_15_16, word),
SyncMode::MatchPartialRepeated(word) => (SyncCheck::CHECK_30_32, word),
SyncMode::MatchFull(word) => (SyncCheck::CHECK_16_16, word),
};
self.0.modify_register(Config::MDMCFG2, |r| {
MDMCFG2(r).modify().sync_mode(mode.value()).bits()
})?;
self.0.write_register(Config::SYNC1, ((word >> 8) & 0xff) as u8)?;
self.0.write_register(Config::SYNC0, (word & 0xff) as u8)?;
Ok(())
}
pub fn set_modulation(&mut self, format: Modulation) -> Result<(), Error<SpiE>> {
use lowlevel::types::ModFormat as MF;
let value = match format {
Modulation::BinaryFrequencyShiftKeying => MF::MOD_2FSK,
Modulation::GaussianFrequencyShiftKeying => MF::MOD_GFSK,
Modulation::OnOffKeying => MF::MOD_ASK_OOK,
Modulation::FourFrequencyShiftKeying => MF::MOD_4FSK,
Modulation::MinimumShiftKeying => MF::MOD_MSK,
};
self.0.modify_register(Config::MDMCFG2, |r| {
MDMCFG2(r).modify().mod_format(value.value()).bits()
})?;
Ok(())
}
pub fn set_address_filter(&mut self, filter: AddressFilter) -> Result<(), Error<SpiE>> {
use lowlevel::types::AddressCheck as AC;
let (mode, addr) = match filter {
AddressFilter::Disabled => (AC::DISABLED, ADDR::default().bits()),
AddressFilter::Device(addr) => (AC::SELF, addr),
AddressFilter::DeviceLowBroadcast(addr) => (AC::SELF_LOW_BROADCAST, addr),
AddressFilter::DeviceHighLowBroadcast(addr) => (AC::SELF_HIGH_LOW_BROADCAST, addr),
};
self.0.modify_register(Config::PKTCTRL1, |r| {
PKTCTRL1(r).modify().adr_chk(mode.value()).bits()
})?;
self.0.write_register(Config::ADDR, addr)?;
Ok(())
}
pub fn set_packet_length(&mut self, length: PacketLength) -> Result<(), Error<SpiE>> {
use lowlevel::types::LengthConfig as LC;
let (format, pktlen) = match length {
PacketLength::Fixed(limit) => (LC::FIXED, limit),
PacketLength::Variable(max_limit) => (LC::VARIABLE, max_limit),
PacketLength::Infinite => (LC::INFINITE, PKTLEN::default().bits()),
};
self.0.modify_register(Config::PKTCTRL0, |r| {
PKTCTRL0(r).modify().length_config(format.value()).bits()
})?;
self.0.write_register(Config::PKTLEN, pktlen)?;
Ok(())
}
pub fn set_radio_mode(&mut self, radio_mode: RadioMode) -> Result<(), Error<SpiE>> {
let target = match radio_mode {
RadioMode::Receive => {
self.set_radio_mode(RadioMode::Idle)?;
self.0.write_strobe(Command::SRX)?;
MachineState::RX
}
RadioMode::Transmit => {
self.set_radio_mode(RadioMode::Idle)?;
self.0.write_strobe(Command::STX)?;
MachineState::TX
}
RadioMode::Idle => {
self.0.write_strobe(Command::SIDLE)?;
MachineState::IDLE
}
RadioMode::Calibrate => {
self.set_radio_mode(RadioMode::Idle)?;
self.0.write_strobe(Command::SCAL)?;
MachineState::IDLE
}
};
self.await_machine_state(target)
}
pub fn reset(&mut self) -> Result<(), Error<SpiE>> {
self.0.write_strobe(Command::SRES)?;
Ok(())
}
#[rustfmt::skip]
pub fn set_defaults(&mut self) -> Result<(), Error<SpiE, >> {
self.0.write_strobe(Command::SRES)?;
self.0.write_register(Config::PKTCTRL0, PKTCTRL0::default()
.white_data(0).bits()
)?;
self.set_synthesizer_if(203_125)?;
self.0.write_register(Config::MDMCFG2, MDMCFG2::default()
.dem_dcfilt_off(1).bits()
)?;
self.set_autocalibration(AutoCalibration::FromIdle)?;
self.0.write_register(Config::AGCCTRL2, AGCCTRL2::default()
.max_lna_gain(0x04).bits()
)?;
Ok(())
}
fn await_machine_state(&mut self, target: MachineState) -> Result<(), Error<SpiE>> {
loop {
let marcstate = MARCSTATE(self.0.read_register(Status::MARCSTATE)?);
if target.value() == marcstate.marc_state() {
break;
}
}
Ok(())
}
fn rx_bytes_available(&mut self) -> Result<u8, Error<SpiE>> {
let mut last = 0;
loop {
let rxbytes = RXBYTES(self.0.read_register(Status::RXBYTES)?);
if rxbytes.rxfifo_overflow() == 1 {
return Err(Error::RxOverflow);
}
let nbytes = rxbytes.num_rxbytes();
if nbytes > 0 && nbytes == last {
break;
}
last = nbytes;
}
Ok(last)
}
pub fn receive(&mut self, addr: &mut u8, buf: &mut [u8]) -> Result<u8, Error<SpiE>> {
match self.rx_bytes_available() {
Ok(_nbytes) => {
let mut length = 0u8;
self.0.read_fifo(addr, &mut length, buf)?;
let lqi = self.0.read_register(Status::LQI)?;
self.await_machine_state(MachineState::IDLE)?;
self.0.write_strobe(Command::SFRX)?;
if (lqi >> 7) != 1 {
Err(Error::CrcMismatch)
} else {
Ok(length)
}
}
Err(err) => {
self.0.write_strobe(Command::SFRX)?;
Err(err)
}
}
}
pub fn set_raw_mode(&mut self) -> Result<(), Error<SpiE>> {
self.0.write_register(Config::IOCFG0, 0x0d)?;
self.0.write_register(Config::PKTCTRL0, 0x30)?;
Ok(())
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Modulation {
BinaryFrequencyShiftKeying,
GaussianFrequencyShiftKeying,
OnOffKeying,
FourFrequencyShiftKeying,
MinimumShiftKeying,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PacketLength {
Fixed(u8),
Variable(u8),
Infinite,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AddressFilter {
Disabled,
Device(u8),
DeviceLowBroadcast(u8),
DeviceHighLowBroadcast(u8),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum RadioMode {
Receive,
Transmit,
Idle,
Calibrate,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SyncMode {
Disabled,
MatchPartial(u16),
MatchPartialRepeated(u16),
MatchFull(u16),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum TargetAmplitude {
Db24 = 0,
Db27 = 1,
Db30 = 2,
Db33 = 3,
Db36 = 4,
Db38 = 5,
Db40 = 6,
Db42 = 7,
}
impl From<TargetAmplitude> for u8 {
fn from(value: TargetAmplitude) -> Self {
value as Self
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum FilterLength {
Samples8 = 0,
Samples16 = 1,
Samples32 = 2,
Samples64 = 3,
}
impl From<FilterLength> for u8 {
fn from(value: FilterLength) -> Self {
value as Self
}
}