use crate::{
OperatingMode, PacketType, Radio, RadioConfig,
params::{LoraSpreadingFactor, ModulationParams8x, PacketParams},
shared::{OpCode, RadioError, Register::Reg8x, Register8x},
};
const TIMING_FACTOR_MS_6X: f32 = 0.015_625;
const F_XTAL_6X: f32 = 32_000_000.;
const F_XTAL_8X: f32 = 52_000_000.;
const FREQ_CONST_6X: f32 = F_XTAL_6X / (1 << 25) as f32;
const FREQ_CONST_8X: f32 = F_XTAL_8X / (1 << 18) as f32;
impl Radio {
pub(crate) fn set_rf_freq(&mut self) -> Result<(), RadioError> {
match &self.config {
RadioConfig::R6x(config) => {
let rf_freq_raw = ((config.rf_freq as f32 / FREQ_CONST_6X) as u32).to_be_bytes();
self.interface.write(&[
OpCode::SetRfFrequency as u8,
rf_freq_raw[0],
rf_freq_raw[1],
rf_freq_raw[2],
rf_freq_raw[3],
])
}
RadioConfig::R8x(config) => {
let rf_freq_raw = ((config.rf_freq as f32 / FREQ_CONST_8X) as u32).to_be_bytes();
self.interface.write(&[
OpCode::SetRfFrequency.val_8x(),
rf_freq_raw[1],
rf_freq_raw[2],
rf_freq_raw[3],
])
}
}
}
pub fn set_mod_params(&mut self) -> Result<(), RadioError> {
match &self.config {
RadioConfig::R6x(config) => {
let mut p1 = 0;
let mut p2 = 0;
let mut p3 = 0;
let mut p4 = 0;
let p5 = 0;
let p6 = 0;
let p7 = 0;
let p8 = 0;
match config.packet_type {
PacketType::Gfsk => {
unimplemented!()
}
PacketType::Lora => {
p1 = config.modulation_params.spreading_factor as u8;
p2 = config.modulation_params.mod_bandwidth as u8;
p3 = config.modulation_params.coding_rate as u8;
p4 = config.modulation_params.low_data_rate_optimization as u8;
}
PacketType::LrFhssFlrc => {
unimplemented!()
}
_ => unimplemented!(),
}
self.interface.write(&[
OpCode::SetModulationParams as u8,
p1,
p2,
p3,
p4,
p5,
p6,
p7,
p8,
])?;
}
RadioConfig::R8x(config) => {
let mut p1 = 0;
let mut p2 = 0;
let mut p3 = 0;
match config.packet_type {
PacketType::Gfsk => {
unimplemented!()
}
PacketType::Lora => match &config.modulation_params {
ModulationParams8x::Lora(m) => {
p1 = m.spreading_factor.val_8x();
p2 = m.mod_bandwidth as u8;
p3 = m.coding_rate as u8;
}
ModulationParams8x::Flrc(_) => {
panic!("Found FLRC modulation params for Lora packet type.")
}
},
PacketType::LrFhssFlrc => match &config.modulation_params {
ModulationParams8x::Lora(_) => {
panic!("Found Lora modulation params for FLRC packet type.")
}
ModulationParams8x::Flrc(m) => {
p1 = m.bitrate as u8;
p2 = m.coding_rate as u8;
p3 = m.bt as u8;
}
},
_ => unimplemented!(),
}
self.interface
.write(&[OpCode::SetModulationParams.val_8x(), p1, p2, p3])?;
if let ModulationParams8x::Lora(m) = &config.modulation_params {
let sf_cfg_val = match m.spreading_factor {
LoraSpreadingFactor::SF5 | LoraSpreadingFactor::SF6 => 0x1e,
LoraSpreadingFactor::SF7 | LoraSpreadingFactor::SF8 => 0x37,
_ => 0x32,
};
self.interface
.write_reg_word(Reg8x(Register8x::SfAdditionalConfiguration), sf_cfg_val)?;
self.interface
.write_reg_word(Reg8x(Register8x::FrequencyErrorCorrection), 0x1)?;
}
}
}
Ok(())
}
pub(crate) fn set_packet_params(&mut self) -> Result<(), RadioError> {
let mut p1 = 0;
let mut p2 = 0;
let mut p3 = 0;
let mut p4 = 0;
let mut p5 = 0;
let mut p6 = 0;
let p7 = 0;
let p8 = 0;
let p9 = 0;
match &self.config {
RadioConfig::R6x(config) => {
if config.packet_params.preamble_len < 10 {
return Err(RadioError::Config);
}
match config.packet_type {
PacketType::Gfsk => {
unimplemented!()
}
PacketType::Lora => {
let preamble_len = config.packet_params.preamble_len.to_be_bytes();
p1 = preamble_len[0];
p2 = preamble_len[1];
p3 = config.packet_params.header_type.val_6x();
p4 = config.packet_params.payload_len;
p5 = config.packet_params.crc_enabled.val_6x();
p6 = config.packet_params.invert_iq.val_6x();
}
PacketType::LrFhssFlrc => {
unimplemented!()
}
_ => unimplemented!(),
}
self.interface.write(&[
OpCode::SetPacketParams as u8,
p1,
p2,
p3,
p4,
p5,
p6,
p7,
p8,
p9,
])
}
RadioConfig::R8x(config) => {
let mut p1 = 0;
let mut p2 = 0;
let mut p3 = 0;
let mut p4 = 0;
let mut p5 = 0;
let mut p6 = 0;
let p7 = 0;
match config.packet_type {
PacketType::Gfsk => {
unimplemented!()
}
PacketType::Lora => {
match &config.packet_params {
PacketParams::Lora(p) => {
let pble_len_maint = p.preamble_len as u8;
let pble_len_exp: u8 = 0;
let preamble_len =
((pble_len_exp & 0xf) << 4) | (pble_len_maint & 0xf);
p1 = preamble_len;
p2 = p.header_type.val_8x();
p3 = p.payload_len;
p4 = p.crc_enabled.val_8x();
p5 = p.invert_iq.val_8x();
}
PacketParams::Flrc(_) => {
panic!("Found FLRC packet params for Lora packet type.")
}
}
}
PacketType::LrFhssFlrc => match &config.packet_params {
PacketParams::Lora(_) => {
panic!("Found Lora packet params for FLRC packet type.")
}
PacketParams::Flrc(p) => {
p1 = p.preamble_len as u8;
p2 = p.sync_word_len as u8;
p3 = p.sync_word_combo as u8;
p4 = p.packet_type as u8;
p5 = p.payload_len;
p6 = p.crc as u8;
}
},
_ => unimplemented!(), }
self.interface.write(&[
OpCode::SetPacketParams.val_8x(),
p1,
p2,
p3,
p4,
p5,
p6,
p7,
])
}
}
}
pub(crate) fn set_pa_config(&mut self) -> Result<(), RadioError> {
match &self.config {
RadioConfig::R6x(config) => {
let (duty_cycle, hp_max) = config.output_power.dutycycle_hpmax();
self.interface
.write(&[OpCode::SetPAConfig as u8, duty_cycle, hp_max, 0, 1])
}
_ => unimplemented!(),
}
}
pub(crate) fn set_tx_params(&mut self) -> Result<(), RadioError> {
let (power, ramp_time) = match &self.config {
RadioConfig::R6x(config) => {
(config.output_power as u8, config.ramp_time as u8) }
RadioConfig::R8x(config) => {
assert!(config.output_power >= -18 && config.output_power <= 13);
((config.output_power + 18) as u8, config.ramp_time as u8) }
};
self.interface
.write(&[OpCode::SetTxParams as u8, power, ramp_time])
}
pub fn set_op_mode(&mut self, mode: OperatingMode) -> Result<(), RadioError> {
match mode {
OperatingMode::Sleep(cfg) => {
self.interface
.write_op_word(OpCode::SetSleep, (cfg as u8) << 2)
}
OperatingMode::StbyRc => self.interface.write_op_word(OpCode::SetStandby, 0),
OperatingMode::StbyOsc => self.interface.write_op_word(OpCode::SetStandby, 1),
OperatingMode::Fs => self.interface.write(&[OpCode::SetFS as u8]),
OperatingMode::Tx(timeout) => {
let (op_code, to_bytes) = match self.config {
RadioConfig::R6x(_) => (OpCode::SetTx as u8, time_bytes_6x(timeout)),
RadioConfig::R8x(_) => (OpCode::SetTx.val_8x(), time_bytes_8x(timeout)),
};
self.interface
.write(&[op_code, to_bytes[0], to_bytes[1], to_bytes[2]])
}
OperatingMode::Rx(timeout) => {
let (op_code, to_bytes) = match self.config {
RadioConfig::R6x(_) => (OpCode::SetRx as u8, time_bytes_6x(timeout)),
RadioConfig::R8x(_) => (OpCode::SetRx.val_8x(), time_bytes_8x(timeout)),
};
self.interface
.write(&[op_code, to_bytes[0], to_bytes[1], to_bytes[2]])
}
}
}
}
pub fn time_bytes_6x(time_ms: f32) -> [u8; 3] {
let result = ((time_ms / TIMING_FACTOR_MS_6X) as u32).to_be_bytes();
[result[1], result[2], result[3]]
}
pub fn time_bytes_8x(time_ms: f32) -> [u8; 3] {
let period_base = ((time_ms / TIMING_FACTOR_MS_6X) as u16).to_be_bytes();
[0x00, period_base[0], period_base[1]]
}