use embassy_time::Duration;
use embedded_hal::digital::OutputPin;
use embedded_hal_async::spi::SpiBus;
use crate::cmd::cmd_regmem::{read_reg_mem32_req, write_reg_mem32_cmd, write_reg_mem_mask32_cmd, ReadRegMem32Rsp};
use crate::constants::*;
use super::{BusyPin, Lr2021, Lr2021Error};
use super::status::{Intr, Status};
pub use super::cmd::cmd_system::*;
use super::radio::{set_rx_cmd, set_tx_cmd};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ChipMode {
DeepSleep,
DeepRetention,
Sleep(u32),
Retention(u32),
StandbyRc,
StandbyXosc,
Fs,
Tx,
Rx,
}
const SIMO_FREQ_LBW : u32 = 4_508_877;
const SIMO_FREQ_HBW : u32 = 2_936_013;
const SIMO_TIME_WIDE : u32 = 0xBD;
const SIMO_TIME_DEFAULT : u32 = 0xFF;
pub fn pllstep_to_hz(val_step: u32) -> u32 {
let val_scaled : u64 = (val_step as u64) * 15625;
(val_scaled >> 14) as u32
}
#[derive(Default, Clone, Copy)]
pub struct RetentionCfg(u8);
impl RetentionCfg {
pub const RET_SIMO : u8 = 1;
pub const RET_LORA_SX127X_SF6_SW : u8 = 2;
pub const RET_LORA_SX127X_HOP : u8 = 4;
pub const RET_CPFSK_DEMOD : u8 = 8;
pub fn new() -> Self {
Self(0)
}
pub fn with_simo(self) -> Self {
Self(self.0 | Self::RET_SIMO)
}
pub fn with_lora_sx127x_sf6_sw(self) -> Self {
Self(self.0 | Self::RET_LORA_SX127X_SF6_SW)
}
pub fn with_lora_sx127x_hopping(self) -> Self {
Self(self.0 | Self::RET_LORA_SX127X_HOP)
}
pub fn with_ble_coded(self) -> Self {
Self(self.0 | Self::RET_CPFSK_DEMOD)
}
pub fn with_wisun_tracking(self) -> Self {
Self(self.0 | Self::RET_CPFSK_DEMOD)
}
pub fn has_simo(self) -> bool {
(self.0 & Self::RET_SIMO) != 0
}
pub fn has_lora_sx127x_sf6_sw(self) -> bool {
(self.0 & Self::RET_LORA_SX127X_SF6_SW) != 0
}
pub fn has_lora_sx127x_hopping(self) -> bool {
(self.0 & Self::RET_LORA_SX127X_HOP) != 0
}
pub fn has_cpfsk_demod(self) -> bool {
(self.0 & Self::RET_CPFSK_DEMOD) != 0
}
}
impl<O,SPI, M> Lr2021<O,SPI, M> where
O: OutputPin, SPI: SpiBus<u8>, M: BusyPin
{
pub async fn get_status(&mut self) -> Result<(Status,Intr), Lr2021Error> {
let req = get_status_req();
let mut rsp = StatusRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok((rsp.status(), rsp.intr()))
}
pub async fn get_errors(&mut self) -> Result<ErrorsRsp, Lr2021Error> {
let req = get_errors_req();
let mut rsp = ErrorsRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp)
}
pub async fn get_version(&mut self) -> Result<VersionRsp, Lr2021Error> {
let req = get_version_req();
let mut rsp = VersionRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp)
}
pub async fn get_and_clear_irq(&mut self) -> Result<Intr, Lr2021Error> {
let req = get_and_clear_irq_req();
let mut rsp = StatusRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp.intr())
}
pub async fn clear_irqs(&mut self, intr: Intr) -> Result<(), Lr2021Error> {
let req = clear_irq_cmd(intr.value());
self.cmd_wr(&req).await
}
pub async fn calibrate(&mut self, pa_offset: bool, meas_unit: bool, aaf: bool, pll: bool, hf_rc: bool, lf_rc: bool) -> Result<(), Lr2021Error> {
let req = calibrate_cmd(pa_offset, meas_unit, aaf, pll, hf_rc, lf_rc);
self.cmd_wr(&req).await
}
pub async fn calib_fe(&mut self, freqs_4m: &[u16]) -> Result<(), Lr2021Error> {
let f0 = freqs_4m.first().copied().unwrap_or(0);
let f1 = freqs_4m.get(1).copied().unwrap_or(0);
let f2 = freqs_4m.get(2).copied().unwrap_or(0);
let req = calib_fe_cmd(f0,f1,f2);
let len = 2 + 2*freqs_4m.len();
self.cmd_wr(&req[..len]).await
}
pub async fn set_chip_mode(&mut self, chip_mode: ChipMode) -> Result<(), Lr2021Error> {
match chip_mode {
ChipMode::DeepSleep => self.cmd_wr(&set_sleep_cmd(false, 0)).await,
ChipMode::DeepRetention => self.cmd_wr(&set_sleep_adv_cmd(false, 1, 0)).await,
ChipMode::Sleep(t) => self.cmd_wr(&set_sleep_adv_cmd(true, 0, t)).await,
ChipMode::Retention(t) => self.cmd_wr(&set_sleep_adv_cmd(true, 1, t)).await,
ChipMode::StandbyRc => self.cmd_wr(&set_standby_cmd(StandbyMode::Rc)).await,
ChipMode::StandbyXosc => self.cmd_wr(&set_standby_cmd(StandbyMode::Xosc)).await,
ChipMode::Fs => self.cmd_wr(&set_fs_cmd()).await,
ChipMode::Tx => self.cmd_wr(&set_tx_cmd()).await,
ChipMode::Rx => self.cmd_wr(&set_rx_cmd()).await,
}
}
pub async fn set_regulator_mode(&mut self, simo_en: bool) -> Result<(), Lr2021Error> {
let mode = if simo_en {SimoUsage::Auto} else {SimoUsage::Off};
let req = set_reg_mode_cmd(mode);
self.cmd_wr(&req).await
}
pub async fn add_register_to_retention(&mut self, slot: u8, addr: u32) -> Result<(), Lr2021Error> {
let req = set_additional_reg_to_retain_cmd(slot, addr);
self.cmd_wr(&req).await
}
pub async fn setup_retention(&mut self, cfg: RetentionCfg) -> Result<(), Lr2021Error> {
let mut slot = 0;
if cfg.has_simo() {
self.add_register_to_retention(slot, ADDR_SIMO_CFG).await?;
slot += 1;
}
if cfg.has_lora_sx127x_sf6_sw() {
self.add_register_to_retention(slot, ADDR_LORA_PARAM).await?;
slot += 1;
}
if cfg.has_lora_sx127x_hopping() {
self.add_register_to_retention(slot, ADDR_LORA_TX_CFG1).await?;
slot += 1;
}
if cfg.has_cpfsk_demod() {
self.add_register_to_retention(slot, ADDR_CPFSK_DEMOD).await?;
slot += 1;
self.add_register_to_retention(slot, ADDR_CPFSK_DETECT).await?;
}
Ok(())
}
pub async fn set_eol_config(&mut self, thr: EolTrim, en: bool) -> Result<(), Lr2021Error> {
let req = set_eol_config_cmd(thr, en);
self.cmd_wr(&req).await
}
pub async fn patch_simo(&mut self, ret_en: Option<u8>) -> Result<(), Lr2021Error> {
let ana_dec = (self.rd_reg(ADDR_ADC_CTRL).await? >> 8) & 3;
let is_hf = (self.rd_reg(ADDR_AAF_CFG).await? &3) == 1;
let v = if !is_hf && ana_dec < 3 {SIMO_TIME_WIDE} else {SIMO_TIME_DEFAULT};
self.wr_reg_mask(ADDR_SIMO_CFG, 0x00FF_0000, v << 16).await?;
let new_freq = if ana_dec==1 {SIMO_FREQ_HBW} else {SIMO_FREQ_LBW};
let curr_freq = self.rd_reg(ADDR_SIMO_FREQ).await?;
if curr_freq != new_freq {
self.wr_reg(ADDR_SIMO_FREQ, new_freq).await?;
let rf_step = self.rd_reg(ADDR_FREQ_RF).await?;
let rf_hz = pllstep_to_hz(rf_step);
self.set_rf(rf_hz).await?;
}
if let Some(slot) = ret_en {
self.add_register_to_retention(slot,ADDR_SIMO_CFG).await?;
}
Ok(())
}
pub async fn set_dio_function(&mut self, dio: DioNum, func: DioFunc, pull_drive: PullDrive) -> Result<(), Lr2021Error> {
let req = set_dio_function_cmd(dio, func, pull_drive);
self.cmd_wr(&req).await
}
pub async fn set_dio_rf_switch(&mut self, dio_num: DioNum, tx_hf: bool, rx_hf: bool, tx_lf: bool, rx_lf: bool, standby: bool) -> Result<(), Lr2021Error> {
let req = set_dio_rf_switch_config_cmd(dio_num, tx_hf, rx_hf, tx_lf, rx_lf, standby);
self.cmd_wr(&req).await
}
pub async fn set_dio_irq(&mut self, dio: DioNum, intr_en: Intr) -> Result<(), Lr2021Error> {
let sleep_pull = if dio==DioNum::Dio5 || dio==DioNum::Dio6 {PullDrive::PullAuto} else {PullDrive::PullUp};
let req = set_dio_function_cmd(dio, DioFunc::Irq, sleep_pull);
self.cmd_wr(&req).await?;
let req = set_dio_irq_config_cmd(dio, intr_en.value());
self.cmd_wr(&req).await
}
pub async fn set_dio_clk_scaling(&mut self, div_scaling: ClkScaling) -> Result<(), Lr2021Error> {
let req = config_clk_outputs_cmd(div_scaling);
self.cmd_wr(&req).await
}
pub async fn set_lf_clk(&mut self, sel: LfClock) -> Result<(), Lr2021Error> {
let req = config_lf_clock_cmd(sel);
self.cmd_wr(&req).await
}
pub async fn set_tcxo(&mut self, volt: TcxoVoltage, start_time: u32) -> Result<(), Lr2021Error> {
let req = set_tcxo_mode_cmd(volt, start_time);
self.cmd_wr(&req).await
}
pub async fn set_xosc_trim(&mut self, xta: u8, xtb: u8, delay_us: Option<u8>) -> Result<(), Lr2021Error> {
let req = set_xosc_cp_trim_adv_cmd(xta, xtb, delay_us.unwrap_or(0));
let len = req.len() - if delay_us.is_some() {1} else {0};
self.cmd_wr(&req[..len]).await
}
pub async fn get_temperature(&mut self, src: TempSrc, res: AdcRes) -> Result<i16, Lr2021Error> {
let req = get_temp_req(src, res);
let mut rsp = TempRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp.temp_celsius())
}
pub async fn set_ntc_param(&mut self, r_ratio: u16, beta: u16, delay: u8) -> Result<(), Lr2021Error> {
let req = set_ntc_params_cmd(r_ratio, beta, delay);
self.cmd_wr(&req).await
}
pub async fn set_temp_comp(&mut self, mode: CompMode, ntc: bool) -> Result<(), Lr2021Error> {
let req = set_temp_comp_cfg_cmd(ntc, mode);
self.cmd_wr(&req).await
}
pub async fn get_vbat(&mut self, res: AdcRes) -> Result<u16, Lr2021Error> {
let req = get_v_bat_req(VbatFormat::Millivolts, res);
let mut rsp = VBatRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp.vbat_mv())
}
pub async fn get_random_number(&mut self) -> Result<u32, Lr2021Error> {
let req = get_random_number_req();
let mut rsp = RandomNumberRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp.random_number())
}
pub async fn rd_reg(&mut self, addr: u32) -> Result<u32, Lr2021Error> {
let req = read_reg_mem32_req(addr, 1);
let mut rsp = ReadRegMem32Rsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp.value())
}
pub async fn rd_mem(&mut self, addr: u32, nb32: u8) -> Result<(), Lr2021Error> {
if nb32 > 40 {
return Err(Lr2021Error::CmdErr);
}
let req = read_reg_mem32_req(addr, nb32);
self.cmd_wr(&req).await?;
self.wait_ready(Duration::from_millis(1)).await?;
self.nss.set_low().map_err(|_| Lr2021Error::Pin)?;
self.buffer.nop();
let rsp_buf = &mut self.buffer.0[..4*nb32 as usize];
self.spi
.transfer_in_place(rsp_buf).await
.map_err(|_| Lr2021Error::Spi)?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)?;
self.buffer.cmd_status().check()
}
pub async fn wr_reg(&mut self, addr: u32, value: u32) -> Result<(), Lr2021Error> {
let req = write_reg_mem32_cmd(addr, value);
self.cmd_wr(&req).await
}
pub async fn wr_reg_mask(&mut self, addr: u32, mask: u32, value: u32) -> Result<(), Lr2021Error> {
let req = write_reg_mem_mask32_cmd(addr, mask, value);
self.cmd_wr(&req).await
}
pub async fn wr_field(&mut self, addr: u32, value: u32, pos: u8, width: u8) -> Result<(), Lr2021Error> {
let mask =
if width >= 32 {0xFFFFFFFF}
else { ((1 << width) - 1) << pos };
let req = write_reg_mem_mask32_cmd(addr, mask, value << pos);
self.cmd_wr(&req).await
}
}