#![allow(unused_assignments)]
#![no_std]
#![crate_type = "lib"]
#![crate_name = "sx127x_lora"]
use embedded_hal::digital::v2::OutputPin;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::spi::{Mode, Phase, Polarity};
use bit_field::BitField;
mod register;
use self::register::Register;
use self::register::IRQ;
use self::register::PaConfig;
pub const MODE: Mode = Mode {
phase: Phase::CaptureOnSecondTransition,
polarity: Polarity::IdleHigh,
};
pub struct LoRa<SPI, CS, RESET, DELAY> {
spi: SPI,
cs: CS,
reset: RESET,
delay: DELAY,
frequency: i64,
pub explicit_header: bool,
pub mode: RadioMode,
}
#[derive(Debug)]
pub enum Error<SPI, CS, RESET> {
Uninformative,
VersionMismatch(u8),
CS(CS),
Reset(RESET),
SPI(SPI),
Transmitting,
}
use Error::*;
impl<SPI, CS, RESET, DELAY, E> LoRa<SPI, CS, RESET, DELAY>
where SPI: Transfer<u8, Error = E> + Write<u8, Error = E>,
CS: OutputPin, RESET: OutputPin, DELAY: DelayMs<u8>{
pub fn new(spi: SPI, cs: CS, reset: RESET, frequency: i64, delay: DELAY)
-> Result<Self, Error<E, CS::Error, RESET::Error>> {
let mut sx127x = LoRa {
spi,
cs,
reset,
delay,
frequency,
explicit_header: true,
mode: RadioMode::Sleep,
};
sx127x.reset.set_low().map_err(Reset)?;
sx127x.delay.delay_ms(10);
sx127x.reset.set_high().map_err(Reset)?;
sx127x.delay.delay_ms(10);
let version = sx127x.read_register(Register::RegVersion.addr())?;
if version == 0x12 {
sx127x.set_mode(RadioMode::Sleep)?;
sx127x.set_frequency(frequency)?;
sx127x.write_register(Register::RegFifoTxBaseAddr.addr(),0)?;
sx127x.write_register(Register::RegFifoRxBaseAddr.addr(),0)?;
let lna = sx127x.read_register(Register::RegLna.addr())?;
sx127x.write_register(Register::RegLna.addr(), lna | 0x03)?;
sx127x.write_register(Register::RegModemConfig3.addr(), 0x04)?;
sx127x.set_mode(RadioMode::Stdby)?;
sx127x.cs.set_high().map_err(CS)?;
Ok(sx127x)
}else{
Err(Error::VersionMismatch(version))
}
}
pub fn transmit_payload_busy(&mut self, buffer: [u8; 255], payload_size: usize)
-> Result<usize,Error<E, CS::Error, RESET::Error>>{
if self.transmitting()? {
Err(Transmitting)
}else{
self.set_mode(RadioMode::Stdby)?;
if self.explicit_header {
self.set_explicit_header_mode()?;
}else{
self.set_implicit_header_mode()?;
}
self.write_register(Register::RegIrqFlags.addr(), 0)?;
self.write_register(Register::RegFifoAddrPtr.addr(), 0)?;
self.write_register(Register::RegPayloadLength.addr(), 0)?;
for byte in buffer.iter().take(payload_size){
self.write_register(Register::RegFifo.addr(), *byte)?;
}
self.write_register(Register::RegPayloadLength.addr(),payload_size as u8)?;
self.set_mode(RadioMode::Tx)?;
while self.transmitting()? {};
Ok(payload_size)
}
}
pub fn set_dio0_tx_done(&mut self) -> Result<(),Error<E, CS::Error, RESET::Error>> {
self.write_register(Register::RegDioMapping1.addr(), 0b01_00_00_00)
}
pub fn transmit_payload(&mut self, buffer: [u8; 255], payload_size: usize)
-> Result<(),Error<E, CS::Error, RESET::Error>>{
if self.transmitting()? {
Err(Transmitting)
}else{
self.set_mode(RadioMode::Stdby)?;
if self.explicit_header {
self.set_explicit_header_mode()?;
}else{
self.set_implicit_header_mode()?;
}
self.write_register(Register::RegIrqFlags.addr(), 0)?;
self.write_register(Register::RegFifoAddrPtr.addr(), 0)?;
self.write_register(Register::RegPayloadLength.addr(), 0)?;
for byte in buffer.iter().take(payload_size){
self.write_register(Register::RegFifo.addr(), *byte)?;
}
self.write_register(Register::RegPayloadLength.addr(),payload_size as u8)?;
self.set_mode(RadioMode::Tx)?;
Ok(())
}
}
pub fn poll_irq(&mut self, timeout_ms: Option<i32>) -> Result<usize,Error<E, CS::Error, RESET::Error>>{
self.set_mode(RadioMode::RxContinuous)?;
let mut count = 0;
match timeout_ms {
Some(value) => {
while (!self.read_register(Register::RegIrqFlags.addr())?.get_bit(6))
&& (count < value) {
count += 1;
self.delay.delay_ms(1);
}
if count >= value {
Err(Uninformative)
}else {
self.clear_irq()?;
Ok(self.read_register(Register::RegRxNbBytes.addr())? as usize)
}
},
None => {
while !self.read_register(Register::RegIrqFlags.addr())?.get_bit(6) {
self.delay.delay_ms(100);
}
self.clear_irq()?;
Ok(self.read_register(Register::RegRxNbBytes.addr())? as usize)
}
}
}
pub fn read_packet(&mut self) -> Result<[u8; 255], Error<E, CS::Error, RESET::Error>> {
let mut buffer = [0 as u8; 255];
self.clear_irq()?;
let size = self.read_register(Register::RegRxNbBytes.addr())?;
let fifo_addr = self.read_register(Register::RegFifoRxCurrentAddr.addr())?;
self.write_register(Register::RegFifoAddrPtr.addr(), fifo_addr)?;
for i in 0..size {
let byte = self.read_register(Register::RegFifo.addr())?;
buffer[i as usize] = byte;
}
self.write_register(Register::RegFifoAddrPtr.addr(), 0)?;
Ok(buffer)
}
pub fn transmitting(&mut self) -> Result<bool, Error<E, CS::Error, RESET::Error>> {
if (self.read_register(Register::RegOpMode.addr())? & RadioMode::Tx.addr())
== RadioMode::Tx.addr() {
Ok(true)
}else{
if (self.read_register(Register::RegIrqFlags.addr())?
& IRQ::IrqTxDoneMask.addr()) == 1{
self.write_register(Register::RegIrqFlags.addr(),
IRQ::IrqTxDoneMask.addr())?;
}
Ok(false)
}
}
pub fn clear_irq(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let irq_flags = self.read_register(Register::RegIrqFlags.addr())?;
self.write_register(Register::RegIrqFlags.addr(), irq_flags)
}
pub fn set_tx_power(&mut self, mut level: i32, output_pin: u8) -> Result<(), Error<E, CS::Error, RESET::Error>>{
if PaConfig::PaOutputRfoPin.addr() == output_pin {
if level < 0 {
level = 0;
} else if level > 14 {
level = 14;
}
self.write_register(Register::RegPaConfig.addr(), (0x70 | level) as u8)
} else {
if level > 17 {
if level > 20 {
level = 20;
}
level -= 3;
self.write_register(Register::RegPaDac.addr(), 0x87)?;
self.set_ocp(140)?;
}else {
if level < 2 {
level = 2;
}
self.write_register(Register::RegPaDac.addr(), 0x84)?;
self.set_ocp(100)?;
}
level -= 2;
self.write_register(Register::RegPaConfig.addr(), PaConfig::PaBoost.addr()
| level as u8)
}
}
pub fn set_ocp(&mut self, ma: u8) -> Result<(), Error<E, CS::Error, RESET::Error>>{
let mut ocp_trim: u8 = 27;
if ma <= 120 {
ocp_trim = (ma - 45) / 5;
} else if ma <=240 {
ocp_trim = (ma + 30) / 10;
}
self.write_register(Register::RegOcp.addr(), 0x20 | (0x1F & ocp_trim))
}
pub fn set_mode(&mut self,mode: RadioMode) -> Result<(), Error<E, CS::Error, RESET::Error>> {
if self.explicit_header {
self.set_explicit_header_mode()?;
}else{
self.set_implicit_header_mode()?;
}
self.write_register(Register::RegOpMode.addr(),RadioMode::LongRangeMode.addr()
| mode.addr())?;
self.mode = mode;
Ok(())
}
pub fn set_frequency(&mut self, freq: i64) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.frequency = freq;
let base = 1;
let frf = (freq * (base << 19)) / 32;
self.write_register(Register::RegFrfMsb.addr(), ((frf & 0x00FF_0000) >> 16) as u8)?;
self.write_register(Register::RegFrfMid.addr(), ((frf & 0x0000_FF00) >> 8) as u8)?;
self.write_register(Register::RegFrfLsb.addr(), (frf & 0x0000_00FF) as u8)
}
fn set_explicit_header_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?;
self.write_register(Register::RegModemConfig1.addr(),reg_modem_config_1 & 0xfe)?;
self.explicit_header = true;
Ok(())
}
fn set_implicit_header_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?;
self.write_register(Register::RegModemConfig1.addr(),reg_modem_config_1 & 0x01)?;
self.explicit_header = false;
Ok(())
}
pub fn set_spreading_factor(&mut self, mut sf: u8) -> Result<(), Error<E, CS::Error, RESET::Error>> {
if sf < 6 {
sf = 6;
} else if sf > 12 {
sf = 12;
}
if sf == 6 {
self.write_register(Register::RegDetectionOptimize.addr(), 0xc5)?;
self.write_register(Register::RegDetectionThreshold.addr(), 0x0c)?;
} else {
self.write_register(Register::RegDetectionOptimize.addr(), 0xc3)?;
self.write_register(Register::RegDetectionThreshold.addr(), 0x0a)?;
}
let modem_config_2 = self.read_register(Register::RegModemConfig2.addr())?;
self.write_register(Register::RegModemConfig2.addr(), (modem_config_2 & 0x0f)
| ((sf << 4) & 0xf0))?;
self.set_ldo_flag()?;
Ok(())
}
pub fn set_signal_bandwidth(&mut self, sbw: i64) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let bw: i64;
match sbw {
7_800 => bw = 0,
10_400 => bw = 1,
15_600 => bw = 2,
20_800 => bw = 3,
31_250 => bw = 4,
41_700 => bw = 5,
62_500 => bw = 6,
125_000 => bw = 7,
250_000 => bw = 8,
_ => bw = 9,
}
let modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?;
self.write_register(Register::RegModemConfig1.addr(), (modem_config_1 & 0x0f)
| ((bw << 4) as u8))?;
self.set_ldo_flag()?;
Ok(())
}
pub fn set_coding_rate_4(&mut self, mut denominator: u8) -> Result<(), Error<E, CS::Error, RESET::Error>> {
if denominator < 5 {
denominator = 5;
} else if denominator > 8 {
denominator = 8;
}
let cr = denominator - 4;
let modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?;
self.write_register( Register::RegModemConfig1.addr(), (modem_config_1 & 0xf1)
| (cr << 1))
}
pub fn set_preamble_length(&mut self, length: i64) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.write_register(Register::RegPreambleMsb.addr(), (length >> 8) as u8)?;
self.write_register(Register::RegPreambleLsb.addr(), length as u8)
}
pub fn set_crc(&mut self, value: bool) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let modem_config_2 = self.read_register(Register::RegModemConfig2.addr())?;
if value {
self.write_register(Register::RegModemConfig2.addr(), modem_config_2 | 0x04)
}else{
self.write_register(Register::RegModemConfig2.addr(), modem_config_2 & 0xfb)
}
}
pub fn set_invert_iq(&mut self, value: bool) -> Result<(), Error<E, CS::Error, RESET::Error>> {
if value {
self.write_register(Register::RegInvertiq.addr(), 0x66)?;
self.write_register(Register::RegInvertiq2.addr(), 0x19)
}else{
self.write_register(Register::RegInvertiq.addr(), 0x27)?;
self.write_register(Register::RegInvertiq2.addr(), 0x1d)
}
}
pub fn get_spreading_factor(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> {
Ok(self.read_register(Register::RegModemConfig2.addr())? >> 4)
}
pub fn get_signal_bandwidth(&mut self) -> Result<i64, Error<E, CS::Error, RESET::Error>> {
let bw = self.read_register(Register::RegModemConfig1.addr())? >> 4;
let bw = match bw {
0 => 7_800,
1 => 10_400,
2 => 15_600,
3 => 20_800,
4 => 31_250,
5 => 41_700,
6 => 62_500,
7 => 125_000,
8 => 250_000,
9 => 500_000,
_ => -1,
};
Ok(bw)
}
pub fn get_packet_rssi(&mut self) -> Result<i32, Error<E, CS::Error, RESET::Error>> {
Ok(i32::from(self.read_register(Register::RegPktRssiValue.addr())?) - 157)
}
pub fn get_packet_snr(&mut self) -> Result<f64, Error<E, CS::Error, RESET::Error>> {
Ok(f64::from(self.read_register(Register::RegPktSnrValue.addr())?))
}
pub fn get_packet_frequency_error(&mut self) -> Result<i64, Error<E, CS::Error, RESET::Error>> {
let mut freq_error: i32 = 0;
freq_error = i32::from(self.read_register( Register::RegFreqErrorMsb.addr())? & 0x7);
freq_error <<= 8i64;
freq_error += i32::from(self.read_register(Register::RegFreqErrorMid.addr())?);
freq_error <<= 8i64;
freq_error += i32::from(self.read_register( Register::RegFreqErrorLsb.addr())?);
let f_xtal = 32_000_000;
let f_error = ((f64::from(freq_error) * (1i64 << 24) as f64) / f64::from(f_xtal)) *
(self.get_signal_bandwidth()? as f64 / 500_000.0f64);
Ok(f_error as i64)
}
fn set_ldo_flag(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let sw = self.get_signal_bandwidth()?;
let symbol_duration = 1000 / (sw / ((1 as i64) << self.get_spreading_factor()?)) ;
let ldo_on = symbol_duration > 16;
let mut config_3 = self.read_register(Register::RegModemConfig3.addr())?;
config_3.set_bit(3,ldo_on);
self.write_register(Register::RegModemConfig3.addr(), config_3)
}
fn read_register(&mut self, reg: u8) -> Result<u8,Error<E, CS::Error, RESET::Error>> {
self.cs.set_low().map_err(CS)?;
let mut buffer = [reg & 0x7f, 0];
let transfer = self.spi.transfer(&mut buffer).map_err(SPI)?;
self.cs.set_high().map_err(CS)?;
Ok(transfer[1])
}
fn write_register(&mut self, reg: u8, byte: u8) -> Result<(),Error<E, CS::Error, RESET::Error>>{
self.cs.set_low().map_err(CS)?;
let buffer = [reg | 0x80, byte];
let write = self.spi.write(& buffer).map_err(SPI)?;
self.cs.set_high().map_err(CS)?;
Ok(write)
}
}
#[derive(Clone, Copy)]
pub enum RadioMode{
LongRangeMode = 0x80,
Sleep = 0x00,
Stdby = 0x01,
Tx = 0x03,
RxContinuous = 0x05,
RxSingle = 0x06,
}
impl RadioMode {
pub fn addr(self) -> u8 {
self as u8
}
}