mod radio_kind_params;
use defmt::debug;
use embedded_hal_async::delay::DelayUs;
use embedded_hal_async::spi::*;
use radio_kind_params::*;
use crate::mod_params::*;
use crate::{InterfaceVariant, RadioKind, SpiInterface};
const LORA_MAC_PUBLIC_SYNCWORD: u16 = 0x3444; const LORA_MAC_PRIVATE_SYNCWORD: u16 = 0x1424; const MAX_NUMBER_REGS_IN_RETENTION: u8 = 4;
const SX126X_XTAL_FREQ: u32 = 32000000;
const SX126X_PLL_STEP_SHIFT_AMOUNT: u32 = 14;
const SX126X_PLL_STEP_SCALED: u32 = SX126X_XTAL_FREQ >> (25 - SX126X_PLL_STEP_SHIFT_AMOUNT);
const SX126X_MAX_LORA_SYMB_NUM_TIMEOUT: u8 = 248;
const BRD_TCXO_WAKEUP_TIME: u32 = 10;
impl ModulationParams {
pub fn new_for_sx1261_2(
spreading_factor: SpreadingFactor,
bandwidth: Bandwidth,
coding_rate: CodingRate,
frequency_in_hz: u32,
) -> Result<Self, RadioError> {
spreading_factor_value(spreading_factor)?;
bandwidth_value(bandwidth)?;
coding_rate_value(coding_rate)?;
if ((bandwidth == Bandwidth::_250KHz) || (bandwidth == Bandwidth::_500KHz)) && (frequency_in_hz < 400_000_000) {
return Err(RadioError::InvalidBandwidthForFrequency);
}
let mut low_data_rate_optimize = 0x00u8;
if (((spreading_factor == SpreadingFactor::_11) || (spreading_factor == SpreadingFactor::_12))
&& (bandwidth == Bandwidth::_125KHz))
|| ((spreading_factor == SpreadingFactor::_12) && (bandwidth == Bandwidth::_250KHz))
{
low_data_rate_optimize = 0x01u8;
}
Ok(Self {
spreading_factor,
bandwidth,
coding_rate,
low_data_rate_optimize,
frequency_in_hz,
})
}
}
impl PacketParams {
pub fn new_for_sx1261_2(
mut preamble_length: u16,
implicit_header: bool,
payload_length: u8,
crc_on: bool,
iq_inverted: bool,
modulation_params: &ModulationParams,
) -> Result<Self, RadioError> {
if ((modulation_params.spreading_factor == SpreadingFactor::_5)
|| (modulation_params.spreading_factor == SpreadingFactor::_6))
&& (preamble_length < 12)
{
preamble_length = 12;
}
Ok(Self {
preamble_length,
implicit_header,
payload_length,
crc_on,
iq_inverted,
})
}
}
pub struct SX1261_2<SPI, IV> {
board_type: BoardType,
intf: SpiInterface<SPI, IV>,
}
impl<SPI, IV> SX1261_2<SPI, IV>
where
SPI: SpiBus<u8> + 'static,
IV: InterfaceVariant + 'static,
{
pub fn new(board_type: BoardType, spi: SPI, mut iv: IV) -> Self {
iv.set_board_type(board_type);
let intf = SpiInterface::new(spi, iv);
Self { board_type, intf }
}
async fn add_register_to_retention_list(&mut self, register: Register) -> Result<(), RadioError> {
let mut buffer = [0x00u8; (1 + (2 * MAX_NUMBER_REGS_IN_RETENTION)) as usize];
self.intf
.read(
&[&[
OpCode::ReadRegister.value(),
Register::RetentionList.addr1(),
Register::RetentionList.addr2(),
0x00u8,
]],
&mut buffer,
None,
)
.await?;
let number_of_registers = buffer[0];
for i in 0..number_of_registers {
if register.addr1() == buffer[(1 + (2 * i)) as usize] && register.addr2() == buffer[(2 + (2 * i)) as usize]
{
return Ok(()); }
}
if number_of_registers < MAX_NUMBER_REGS_IN_RETENTION {
buffer[0] += 1; buffer[(1 + (2 * number_of_registers)) as usize] = register.addr1();
buffer[(2 + (2 * number_of_registers)) as usize] = register.addr2();
let register = [
OpCode::WriteRegister.value(),
Register::RetentionList.addr1(),
Register::RetentionList.addr2(),
];
self.intf.write(&[®ister, &buffer], false).await
} else {
Err(RadioError::RetentionListExceeded)
}
}
async fn set_lora_symbol_num_timeout(&mut self, symbol_num: u16) -> Result<(), RadioError> {
let mut exp = 0u8;
let mut reg;
let mut mant = ((core::cmp::min(symbol_num, SX126X_MAX_LORA_SYMB_NUM_TIMEOUT as u16) as u8) + 1) >> 1;
while mant > 31 {
mant = (mant + 3) >> 2;
exp += 1;
}
reg = mant << ((2 * exp) + 1);
let op_code_and_timeout = [OpCode::SetLoRaSymbTimeout.value(), reg];
self.intf.write(&[&op_code_and_timeout], false).await?;
if symbol_num != 0 {
reg = exp + (mant << 3);
let register_and_timeout = [
OpCode::WriteRegister.value(),
Register::SynchTimeout.addr1(),
Register::SynchTimeout.addr2(),
reg,
];
self.intf.write(&[®ister_and_timeout], false).await?;
}
Ok(())
}
async fn set_pa_config(
&mut self,
pa_duty_cycle: u8,
hp_max: u8,
device_sel: u8,
pa_lut: u8,
) -> Result<(), RadioError> {
let op_code_and_pa_config = [OpCode::SetPAConfig.value(), pa_duty_cycle, hp_max, device_sel, pa_lut];
self.intf.write(&[&op_code_and_pa_config], false).await
}
fn timeout_1(timeout: u32) -> u8 {
((timeout >> 16) & 0xFF) as u8
}
fn timeout_2(timeout: u32) -> u8 {
((timeout >> 8) & 0xFF) as u8
}
fn timeout_3(timeout: u32) -> u8 {
(timeout & 0xFF) as u8
}
fn convert_freq_in_hz_to_pll_step(freq_in_hz: u32) -> u32 {
let steps_int = freq_in_hz / SX126X_PLL_STEP_SCALED;
let steps_frac = freq_in_hz - (steps_int * SX126X_PLL_STEP_SCALED);
(steps_int << SX126X_PLL_STEP_SHIFT_AMOUNT)
+ (((steps_frac << SX126X_PLL_STEP_SHIFT_AMOUNT) + (SX126X_PLL_STEP_SCALED >> 1)) / SX126X_PLL_STEP_SCALED)
}
}
impl<SPI, IV> RadioKind for SX1261_2<SPI, IV>
where
SPI: SpiBus<u8> + 'static,
IV: InterfaceVariant + 'static,
{
fn get_board_type(&self) -> BoardType {
self.board_type
}
async fn reset(&mut self, delay: &mut impl DelayUs) -> Result<(), RadioError> {
self.intf.iv.reset(delay).await
}
async fn ensure_ready(&mut self, mode: RadioMode) -> Result<(), RadioError> {
if mode == RadioMode::Sleep || mode == RadioMode::ReceiveDutyCycle {
let op_code_and_null = [OpCode::GetStatus.value(), 0x00u8];
self.intf.write(&[&op_code_and_null], false).await?;
} else {
self.intf.iv.wait_on_busy().await?;
}
Ok(())
}
async fn init_rf_switch(&mut self) -> Result<(), RadioError> {
if self.board_type != BoardType::Stm32wlSx1262 {
let op_code_and_indicator = [OpCode::SetRFSwitchMode.value(), true as u8];
self.intf.write(&[&op_code_and_indicator], false).await?;
}
Ok(())
}
async fn set_standby(&mut self) -> Result<(), RadioError> {
let op_code_and_standby_mode = [OpCode::SetStandby.value(), StandbyMode::RC.value()];
self.intf.write(&[&op_code_and_standby_mode], false).await?;
self.intf.iv.disable_rf_switch().await
}
async fn set_sleep(&mut self, delay: &mut impl DelayUs) -> Result<bool, RadioError> {
self.intf.iv.disable_rf_switch().await?;
let sleep_params = SleepParams {
wakeup_rtc: false,
reset: false,
warm_start: true,
};
let op_code_and_sleep_params = [OpCode::SetSleep.value(), sleep_params.value()];
self.intf.write(&[&op_code_and_sleep_params], true).await?;
delay.delay_ms(2).await;
Ok(sleep_params.warm_start) }
async fn set_lora_modem(&mut self, enable_public_network: bool) -> Result<(), RadioError> {
let op_code_and_packet_type = [OpCode::SetPacketType.value(), PacketType::LoRa.value()];
self.intf.write(&[&op_code_and_packet_type], false).await?;
if enable_public_network {
let register_and_syncword = [
OpCode::WriteRegister.value(),
Register::LoRaSyncword.addr1(),
Register::LoRaSyncword.addr2(),
((LORA_MAC_PUBLIC_SYNCWORD >> 8) & 0xFF) as u8,
(LORA_MAC_PUBLIC_SYNCWORD & 0xFF) as u8,
];
self.intf.write(&[®ister_and_syncword], false).await?;
} else {
let register_and_syncword = [
OpCode::WriteRegister.value(),
Register::LoRaSyncword.addr1(),
Register::LoRaSyncword.addr2(),
((LORA_MAC_PRIVATE_SYNCWORD >> 8) & 0xFF) as u8,
(LORA_MAC_PRIVATE_SYNCWORD & 0xFF) as u8,
];
self.intf.write(&[®ister_and_syncword], false).await?;
}
Ok(())
}
async fn set_oscillator(&mut self) -> Result<(), RadioError> {
let voltage = if self.board_type != BoardType::HeltecWifiLoraV31262 {
TcxoCtrlVoltage::Ctrl1V7.value() & 0x07 } else {
TcxoCtrlVoltage::Ctrl1V8.value() & 0x07
};
let timeout = BRD_TCXO_WAKEUP_TIME << 6; let op_code_and_tcxo_control = [
OpCode::SetTCXOMode.value(),
voltage,
Self::timeout_1(timeout),
Self::timeout_2(timeout),
Self::timeout_3(timeout),
];
self.intf.write(&[&op_code_and_tcxo_control], false).await
}
async fn set_regulator_mode(&mut self) -> Result<(), RadioError> {
let op_code_and_regulator_mode = [OpCode::SetRegulatorMode.value(), RegulatorMode::UseDCDC.value()];
self.intf.write(&[&op_code_and_regulator_mode], false).await
}
async fn set_tx_rx_buffer_base_address(
&mut self,
tx_base_addr: usize,
rx_base_addr: usize,
) -> Result<(), RadioError> {
if tx_base_addr > 255 || rx_base_addr > 255 {
return Err(RadioError::InvalidBaseAddress(tx_base_addr, rx_base_addr));
}
let op_code_and_base_addrs = [
OpCode::SetBufferBaseAddress.value(),
tx_base_addr as u8,
rx_base_addr as u8,
];
self.intf.write(&[&op_code_and_base_addrs], false).await
}
async fn set_tx_power_and_ramp_time(
&mut self,
output_power: i32,
mdltn_params: Option<&ModulationParams>,
_tx_boosted_if_possible: bool,
is_tx_prep: bool,
) -> Result<(), RadioError> {
let tx_params_power;
let ramp_time = match is_tx_prep {
true => RampTime::Ramp40Us, false => RampTime::Ramp200Us, };
let chip_type: ChipType = self.board_type.into();
if chip_type == ChipType::Sx1261 {
if !(-17..=15).contains(&output_power) {
return Err(RadioError::InvalidOutputPower);
}
if output_power == 15 {
if let Some(m_p) = mdltn_params {
if m_p.frequency_in_hz < 400_000_000 {
return Err(RadioError::InvalidOutputPowerForFrequency);
}
}
}
match output_power {
15 => {
self.set_pa_config(0x06, 0x00, 0x01, 0x01).await?;
tx_params_power = 14;
}
14 => {
self.set_pa_config(0x04, 0x00, 0x01, 0x01).await?;
tx_params_power = 14;
}
10 => {
self.set_pa_config(0x01, 0x00, 0x01, 0x01).await?;
tx_params_power = 14;
}
_ => {
self.set_pa_config(0x04, 0x00, 0x01, 0x01).await?;
tx_params_power = output_power as u8;
}
}
} else {
if !(-9..=22).contains(&output_power) {
return Err(RadioError::InvalidOutputPower);
}
let mut tx_clamp_cfg = [0x00u8];
self.intf
.read(
&[&[
OpCode::ReadRegister.value(),
Register::TxClampCfg.addr1(),
Register::TxClampCfg.addr2(),
0x00u8,
]],
&mut tx_clamp_cfg,
None,
)
.await?;
tx_clamp_cfg[0] |= 0x0F << 1;
let register_and_tx_clamp_cfg = [
OpCode::WriteRegister.value(),
Register::TxClampCfg.addr1(),
Register::TxClampCfg.addr2(),
tx_clamp_cfg[0],
];
self.intf.write(&[®ister_and_tx_clamp_cfg], false).await?;
match output_power {
22 => {
self.set_pa_config(0x04, 0x07, 0x00, 0x01).await?;
tx_params_power = 22;
}
20 => {
self.set_pa_config(0x03, 0x05, 0x00, 0x01).await?;
tx_params_power = 22;
}
17 => {
self.set_pa_config(0x02, 0x03, 0x00, 0x01).await?;
tx_params_power = 22;
}
14 => {
self.set_pa_config(0x02, 0x02, 0x00, 0x01).await?;
tx_params_power = 22;
}
_ => {
self.set_pa_config(0x04, 0x07, 0x00, 0x01).await?;
tx_params_power = output_power as u8;
}
}
}
debug!("tx power = {}", tx_params_power);
let op_code_and_tx_params = [OpCode::SetTxParams.value(), tx_params_power, ramp_time.value()];
self.intf.write(&[&op_code_and_tx_params], false).await
}
async fn update_retention_list(&mut self) -> Result<(), RadioError> {
self.add_register_to_retention_list(Register::RxGain).await?;
self.add_register_to_retention_list(Register::TxModulation).await
}
async fn set_modulation_params(&mut self, mdltn_params: &ModulationParams) -> Result<(), RadioError> {
let spreading_factor_val = spreading_factor_value(mdltn_params.spreading_factor)?;
let bandwidth_val = bandwidth_value(mdltn_params.bandwidth)?;
let coding_rate_val = coding_rate_value(mdltn_params.coding_rate)?;
debug!(
"sf = {}, bw = {}, cr = {}",
spreading_factor_val, bandwidth_val, coding_rate_val
);
let op_code_and_mod_params = [
OpCode::SetModulationParams.value(),
spreading_factor_val,
bandwidth_val,
coding_rate_val,
mdltn_params.low_data_rate_optimize,
];
self.intf.write(&[&op_code_and_mod_params], false).await?;
let mut tx_mod = [0x00u8];
self.intf
.read(
&[&[
OpCode::ReadRegister.value(),
Register::TxModulation.addr1(),
Register::TxModulation.addr2(),
0x00u8,
]],
&mut tx_mod,
None,
)
.await?;
if mdltn_params.bandwidth == Bandwidth::_500KHz {
let register_and_tx_mod_update = [
OpCode::WriteRegister.value(),
Register::TxModulation.addr1(),
Register::TxModulation.addr2(),
tx_mod[0] & (!(1 << 2)),
];
self.intf.write(&[®ister_and_tx_mod_update], false).await
} else {
let register_and_tx_mod_update = [
OpCode::WriteRegister.value(),
Register::TxModulation.addr1(),
Register::TxModulation.addr2(),
tx_mod[0] | (1 << 2),
];
self.intf.write(&[®ister_and_tx_mod_update], false).await
}
}
async fn set_packet_params(&mut self, pkt_params: &PacketParams) -> Result<(), RadioError> {
let op_code_and_pkt_params = [
OpCode::SetPacketParams.value(),
((pkt_params.preamble_length >> 8) & 0xFF) as u8,
(pkt_params.preamble_length & 0xFF) as u8,
pkt_params.implicit_header as u8,
pkt_params.payload_length,
pkt_params.crc_on as u8,
pkt_params.iq_inverted as u8,
];
self.intf.write(&[&op_code_and_pkt_params], false).await
}
async fn calibrate_image(&mut self, frequency_in_hz: u32) -> Result<(), RadioError> {
let mut cal_freq = [0x00u8, 0x00u8];
if frequency_in_hz > 900000000 {
cal_freq[0] = 0xE1;
cal_freq[1] = 0xE9;
} else if frequency_in_hz > 850000000 {
cal_freq[0] = 0xD7;
cal_freq[1] = 0xDB;
} else if frequency_in_hz > 770000000 {
cal_freq[0] = 0xC1;
cal_freq[1] = 0xC5;
} else if frequency_in_hz > 460000000 {
cal_freq[0] = 0x75;
cal_freq[1] = 0x81;
} else if frequency_in_hz > 425000000 {
cal_freq[0] = 0x6B;
cal_freq[1] = 0x6F;
}
let op_code_and_cal_freq = [OpCode::CalibrateImage.value(), cal_freq[0], cal_freq[1]];
self.intf.write(&[&op_code_and_cal_freq], false).await
}
async fn set_channel(&mut self, frequency_in_hz: u32) -> Result<(), RadioError> {
debug!("channel = {}", frequency_in_hz);
let freq_in_pll_steps = Self::convert_freq_in_hz_to_pll_step(frequency_in_hz);
let op_code_and_pll_steps = [
OpCode::SetRFFrequency.value(),
((freq_in_pll_steps >> 24) & 0xFF) as u8,
((freq_in_pll_steps >> 16) & 0xFF) as u8,
((freq_in_pll_steps >> 8) & 0xFF) as u8,
(freq_in_pll_steps & 0xFF) as u8,
];
self.intf.write(&[&op_code_and_pll_steps], false).await
}
async fn set_payload(&mut self, payload: &[u8]) -> Result<(), RadioError> {
let op_code_and_offset = [OpCode::WriteBuffer.value(), 0x00u8];
self.intf.write(&[&op_code_and_offset, payload], false).await
}
async fn do_tx(&mut self, timeout_in_ms: u32) -> Result<(), RadioError> {
self.intf.iv.enable_rf_switch_tx().await?;
let op_code_and_timeout = [
OpCode::SetTx.value(),
Self::timeout_1(timeout_in_ms),
Self::timeout_2(timeout_in_ms),
Self::timeout_3(timeout_in_ms),
];
self.intf.write(&[&op_code_and_timeout], false).await
}
async fn do_rx(
&mut self,
rx_pkt_params: &PacketParams,
duty_cycle_params: Option<&DutyCycleParams>,
rx_continuous: bool,
rx_boosted_if_supported: bool,
symbol_timeout: u16,
rx_timeout_in_ms: u32,
) -> Result<(), RadioError> {
let mut symbol_timeout_final = symbol_timeout;
let mut rx_timeout_in_ms_final = rx_timeout_in_ms << 6;
if let Some(&_duty_cycle) = duty_cycle_params {
if rx_continuous {
return Err(RadioError::DutyCycleRxContinuousUnsupported);
} else {
symbol_timeout_final = 0;
}
}
self.intf.iv.enable_rf_switch_rx().await?;
if rx_continuous {
symbol_timeout_final = 0;
rx_timeout_in_ms_final = 0x00ffffffu32;
}
let mut rx_gain_final = 0x94u8;
if rx_boosted_if_supported {
rx_gain_final = 0x96u8;
}
let op_code_and_false_flag = [OpCode::SetStopRxTimerOnPreamble.value(), 0x00u8];
self.intf.write(&[&op_code_and_false_flag], false).await?;
self.set_lora_symbol_num_timeout(symbol_timeout_final).await?;
let mut iq_polarity = [0x00u8];
self.intf
.read(
&[&[
OpCode::ReadRegister.value(),
Register::IQPolarity.addr1(),
Register::IQPolarity.addr2(),
0x00u8,
]],
&mut iq_polarity,
None,
)
.await?;
if rx_pkt_params.iq_inverted {
let register_and_iq_polarity = [
OpCode::WriteRegister.value(),
Register::IQPolarity.addr1(),
Register::IQPolarity.addr2(),
iq_polarity[0] & (!(1 << 2)),
];
self.intf.write(&[®ister_and_iq_polarity], false).await?;
} else {
let register_and_iq_polarity = [
OpCode::WriteRegister.value(),
Register::IQPolarity.addr1(),
Register::IQPolarity.addr2(),
iq_polarity[0] | (1 << 2),
];
self.intf.write(&[®ister_and_iq_polarity], false).await?;
}
let register_and_rx_gain = [
OpCode::WriteRegister.value(),
Register::RxGain.addr1(),
Register::RxGain.addr2(),
rx_gain_final,
];
self.intf.write(&[®ister_and_rx_gain], false).await?;
match duty_cycle_params {
Some(&duty_cycle) => {
let op_code_and_duty_cycle = [
OpCode::SetRxDutyCycle.value(),
Self::timeout_1(duty_cycle.rx_time),
Self::timeout_2(duty_cycle.rx_time),
Self::timeout_3(duty_cycle.rx_time),
Self::timeout_1(duty_cycle.sleep_time),
Self::timeout_2(duty_cycle.sleep_time),
Self::timeout_3(duty_cycle.sleep_time),
];
self.intf.write(&[&op_code_and_duty_cycle], false).await
}
None => {
let op_code_and_timeout = [
OpCode::SetRx.value(),
Self::timeout_1(rx_timeout_in_ms_final),
Self::timeout_2(rx_timeout_in_ms_final),
Self::timeout_3(rx_timeout_in_ms_final),
];
self.intf.write(&[&op_code_and_timeout], false).await
}
}
}
async fn get_rx_payload(
&mut self,
rx_pkt_params: &PacketParams,
receiving_buffer: &mut [u8],
) -> Result<u8, RadioError> {
let op_code = [OpCode::GetRxBufferStatus.value()];
let mut rx_buffer_status = [0x00u8; 2];
let read_status = self.intf.read_with_status(&[&op_code], &mut rx_buffer_status).await?;
if OpStatusErrorMask::is_error(read_status) {
return Err(RadioError::OpError(read_status));
}
let mut payload_length_buffer = [0x00u8];
if rx_pkt_params.implicit_header {
self.intf
.read(
&[&[
OpCode::ReadRegister.value(),
Register::PayloadLength.addr1(),
Register::PayloadLength.addr2(),
0x00u8,
]],
&mut payload_length_buffer,
None,
)
.await?;
} else {
payload_length_buffer[0] = rx_buffer_status[0];
}
let payload_length = payload_length_buffer[0];
let offset = rx_buffer_status[1];
if (payload_length as usize) > receiving_buffer.len() {
Err(RadioError::PayloadSizeMismatch(
payload_length as usize,
receiving_buffer.len(),
))
} else {
self.intf
.read(
&[&[OpCode::ReadBuffer.value(), offset, 0x00u8]],
receiving_buffer,
Some(payload_length),
)
.await?;
Ok(payload_length)
}
}
async fn get_rx_packet_status(&mut self) -> Result<PacketStatus, RadioError> {
let op_code = [OpCode::GetPacketStatus.value()];
let mut pkt_status = [0x00u8; 3];
let read_status = self.intf.read_with_status(&[&op_code], &mut pkt_status).await?;
if OpStatusErrorMask::is_error(read_status) {
return Err(RadioError::OpError(read_status));
}
let rssi = ((-(pkt_status[0] as i32)) >> 1) as i16;
let snr = (((pkt_status[1] as i8) + 2) >> 2) as i16;
let _signal_rssi = ((-(pkt_status[2] as i32)) >> 1) as i16; Ok(PacketStatus { rssi, snr })
}
async fn do_cad(
&mut self,
mdltn_params: &ModulationParams,
rx_boosted_if_supported: bool,
) -> Result<(), RadioError> {
self.intf.iv.enable_rf_switch_rx().await?;
let mut rx_gain_final = 0x94u8;
if rx_boosted_if_supported {
rx_gain_final = 0x96u8;
}
let register_and_rx_gain = [
OpCode::WriteRegister.value(),
Register::RxGain.addr1(),
Register::RxGain.addr2(),
rx_gain_final,
];
self.intf.write(&[®ister_and_rx_gain], false).await?;
let spreading_factor_val = spreading_factor_value(mdltn_params.spreading_factor)?;
let op_code_and_cad_params = [
OpCode::SetCADParams.value(),
CADSymbols::_8.value(), spreading_factor_val + 13u8, 10u8, 0x00u8, 0x00u8, 0x00u8,
0x00u8,
];
self.intf.write(&[&op_code_and_cad_params], false).await?;
let op_code_for_set_cad = [OpCode::SetCAD.value()];
self.intf.write(&[&op_code_for_set_cad], false).await
}
async fn set_irq_params(&mut self, radio_mode: Option<RadioMode>) -> Result<(), RadioError> {
let mut irq_mask: u16 = IrqMask::None.value();
let mut dio1_mask: u16 = IrqMask::None.value();
let dio2_mask: u16 = IrqMask::None.value();
let dio3_mask: u16 = IrqMask::None.value();
match radio_mode {
Some(RadioMode::Standby) => {
irq_mask = IrqMask::All.value();
dio1_mask = IrqMask::All.value();
}
Some(RadioMode::Transmit) => {
irq_mask = IrqMask::TxDone.value() | IrqMask::RxTxTimeout.value();
dio1_mask = IrqMask::TxDone.value() | IrqMask::RxTxTimeout.value();
}
Some(RadioMode::Receive) | Some(RadioMode::ReceiveDutyCycle) => {
irq_mask = IrqMask::All.value();
dio1_mask = IrqMask::All.value();
}
Some(RadioMode::ChannelActivityDetection) => {
irq_mask = IrqMask::CADDone.value() | IrqMask::CADActivityDetected.value();
dio1_mask = IrqMask::CADDone.value() | IrqMask::CADActivityDetected.value();
}
_ => {}
}
let op_code_and_masks = [
OpCode::CfgDIOIrq.value(),
((irq_mask >> 8) & 0x00FF) as u8,
(irq_mask & 0x00FF) as u8,
((dio1_mask >> 8) & 0x00FF) as u8,
(dio1_mask & 0x00FF) as u8,
((dio2_mask >> 8) & 0x00FF) as u8,
(dio2_mask & 0x00FF) as u8,
((dio3_mask >> 8) & 0x00FF) as u8,
(dio3_mask & 0x00FF) as u8,
];
self.intf.write(&[&op_code_and_masks], false).await
}
async fn process_irq(
&mut self,
radio_mode: RadioMode,
rx_continuous: bool,
cad_activity_detected: Option<&mut bool>,
) -> Result<(), RadioError> {
loop {
debug!("process_irq loop entered");
self.intf.iv.await_irq().await?;
let op_code = [OpCode::GetIrqStatus.value()];
let mut irq_status = [0x00u8, 0x00u8];
let read_status = self.intf.read_with_status(&[&op_code], &mut irq_status).await?;
if OpStatusErrorMask::is_error(read_status) {
return Err(RadioError::OpError(read_status));
}
let irq_flags = ((irq_status[0] as u16) << 8) | (irq_status[1] as u16);
let op_code_and_irq_status = [OpCode::ClrIrqStatus.value(), irq_status[0], irq_status[1]];
self.intf.write(&[&op_code_and_irq_status], false).await?;
debug!(
"process_irq satisfied: irq_flags = 0x{:x} in radio mode {}",
irq_flags, radio_mode
);
if (irq_flags & IrqMask::HeaderValid.value()) == IrqMask::HeaderValid.value() {
debug!("HeaderValid in radio mode {}", radio_mode);
}
if (irq_flags & IrqMask::PreambleDetected.value()) == IrqMask::PreambleDetected.value() {
debug!("PreambleDetected in radio mode {}", radio_mode);
}
if (irq_flags & IrqMask::SyncwordValid.value()) == IrqMask::SyncwordValid.value() {
debug!("SyncwordValid in radio mode {}", radio_mode);
}
if radio_mode == RadioMode::Transmit {
if (irq_flags & IrqMask::TxDone.value()) == IrqMask::TxDone.value() {
debug!("TxDone in radio mode {}", radio_mode);
return Ok(());
}
if (irq_flags & IrqMask::RxTxTimeout.value()) == IrqMask::RxTxTimeout.value() {
debug!("RxTxTimeout in radio mode {}", radio_mode);
return Err(RadioError::TransmitTimeout);
}
} else if (radio_mode == RadioMode::Receive) || (radio_mode == RadioMode::ReceiveDutyCycle) {
if (irq_flags & IrqMask::HeaderError.value()) == IrqMask::HeaderError.value() {
debug!("HeaderError in radio mode {}", radio_mode);
}
if (irq_flags & IrqMask::CRCError.value()) == IrqMask::CRCError.value() {
debug!("CRCError in radio mode {}", radio_mode);
}
if (irq_flags & IrqMask::RxDone.value()) == IrqMask::RxDone.value() {
debug!("RxDone in radio mode {}", radio_mode);
if !rx_continuous {
let register_and_clear = [
OpCode::WriteRegister.value(),
Register::RTCCtrl.addr1(),
Register::RTCCtrl.addr2(),
0x00u8,
];
self.intf.write(&[®ister_and_clear], false).await?;
let mut evt_clr = [0x00u8];
self.intf
.read(
&[&[
OpCode::ReadRegister.value(),
Register::EvtClr.addr1(),
Register::EvtClr.addr2(),
0x00u8,
]],
&mut evt_clr,
None,
)
.await?;
evt_clr[0] |= 1 << 1;
let register_and_evt_clear = [
OpCode::WriteRegister.value(),
Register::EvtClr.addr1(),
Register::EvtClr.addr2(),
evt_clr[0],
];
self.intf.write(&[®ister_and_evt_clear], false).await?;
}
return Ok(());
}
if (irq_flags & IrqMask::RxTxTimeout.value()) == IrqMask::RxTxTimeout.value() {
debug!("RxTxTimeout in radio mode {}", radio_mode);
return Err(RadioError::ReceiveTimeout);
}
} else if radio_mode == RadioMode::ChannelActivityDetection
&& (irq_flags & IrqMask::CADDone.value()) == IrqMask::CADDone.value()
{
debug!("CADDone in radio mode {}", radio_mode);
if cad_activity_detected.is_some() {
*(cad_activity_detected.unwrap()) =
(irq_flags & IrqMask::CADActivityDetected.value()) == IrqMask::CADActivityDetected.value();
}
return Ok(());
}
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn power_level_negative_value_conversion() {
let mut i32_val: i32 = -17;
assert_eq!(i32_val as u8, 0xefu8);
i32_val = -9;
assert_eq!(i32_val as u8, 0xf7u8);
}
}