Skip to content

Commit

Permalink
extend PhyRxTx to handle antenna gain and max power
Browse files Browse the repository at this point in the history
  • Loading branch information
lthiery committed Nov 8, 2023
1 parent 063453b commit 7dffe22
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 11 deletions.
17 changes: 12 additions & 5 deletions device/src/async_device/lora_radio.rs
Expand Up @@ -6,16 +6,19 @@ use lora_phy::mod_params::{BoardType, ChipType, RadioError};
use lora_phy::mod_traits::RadioKind;
use lora_phy::{DelayUs, LoRa};

/// LoRa radio using the physical layer API in the external lora-phy crate
pub struct LoRaRadio<RK, DLY>
/// LoRa radio using the physical layer API in the external lora-phy crate.
///
/// The const generic P is the max power the radio may be instructed to transmit at. The const
/// generic G is the antenna gain and board loss in dBi.
pub struct LoRaRadio<RK, DLY, const P: u8, const G: i8 = 0>
where
RK: RadioKind,
DLY: DelayUs,
{
pub(crate) lora: LoRa<RK, DLY>,
rx_pkt_params: Option<lora_phy::mod_params::PacketParams>,
}
impl<RK, DLY> LoRaRadio<RK, DLY>
impl<RK, DLY, const P: u8, const G: i8> LoRaRadio<RK, DLY, P, G>
where
RK: RadioKind,
DLY: DelayUs,
Expand All @@ -26,7 +29,7 @@ where
}

/// Provide the timing values for boards supported by the external lora-phy crate
impl<RK, DLY> Timings for LoRaRadio<RK, DLY>
impl<RK, DLY, const P: u8, const G: i8> Timings for LoRaRadio<RK, DLY, P, G>
where
RK: RadioKind,
DLY: DelayUs,
Expand Down Expand Up @@ -63,13 +66,17 @@ impl From<RadioError> for Error {

/// Provide the LoRa physical layer rx/tx interface for boards supported by the external lora-phy
/// crate
impl<RK, DLY> PhyRxTx for LoRaRadio<RK, DLY>
impl<RK, DLY, const P: u8, const G: i8> PhyRxTx for LoRaRadio<RK, DLY, P, G>
where
RK: RadioKind,
DLY: DelayUs,
{
type PhyError = Error;

const ANTENNA_GAIN: i8 = G;

const MAX_RADIO_POWER: u8 = P;

async fn tx(&mut self, config: TxConfig, buffer: &[u8]) -> Result<u32, Self::PhyError> {
let mdltn_params = self.lora.create_modulation_params(
config.rf.bb.sf,
Expand Down
2 changes: 1 addition & 1 deletion device/src/async_device/mod.rs
Expand Up @@ -147,7 +147,7 @@ where
rng: G,
session: Option<Session>,
) -> Self {
let mut mac = Mac::new(region);
let mut mac = Mac::new(region, R::MAX_RADIO_POWER, R::ANTENNA_GAIN);
if let Some(session) = session {
mac.set_session(session);
}
Expand Down
7 changes: 7 additions & 0 deletions device/src/async_device/radio.rs
Expand Up @@ -29,6 +29,13 @@ pub trait PhyRxTx: Sized {
#[cfg(not(feature = "defmt"))]
type PhyError;

/// Board-specific antenna gain and power loss in dBi.
const ANTENNA_GAIN: i8 = 0;

/// Maximum power (dBm) that the radio is able to output. When preparing instructions for radio,
/// the value of maximum power will be used as an upper bound.
const MAX_RADIO_POWER: u8;

/// Transmit data buffer with the given transceiver configuration. The returned future
/// should only complete once data have been transmitted.
async fn tx(&mut self, config: TxConfig, buf: &[u8]) -> Result<u32, Self::PhyError>;
Expand Down
4 changes: 4 additions & 0 deletions device/src/async_device/test/radio.rs
Expand Up @@ -31,6 +31,10 @@ pub struct TestRadio {
impl PhyRxTx for TestRadio {
type PhyError = &'static str;

const MAX_RADIO_POWER: u8 = 26;

const ANTENNA_GAIN: i8 = 0;

async fn tx(&mut self, config: TxConfig, buffer: &[u8]) -> Result<u32, Self::PhyError> {
let length = buffer.len();
// stash the uplink, to be consumed by channel or by rx handler
Expand Down
1 change: 1 addition & 0 deletions device/src/lib.rs
@@ -1,6 +1,7 @@
#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "async", feature(async_fn_in_trait))]
#![allow(incomplete_features)]
//#![feature(generic_const_exprs)]
use core::default::Default;
use heapless::Vec;

Expand Down
20 changes: 17 additions & 3 deletions device/src/mac/mod.rs
Expand Up @@ -36,6 +36,7 @@ pub(crate) enum Window {

#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// LoRaWAN Session and Network Configurations
pub struct Configuration {
pub(crate) data_rate: region::DR,
rx1_delay: u32,
Expand Down Expand Up @@ -74,9 +75,15 @@ impl Configuration {
pub(crate) struct Mac {
pub configuration: Configuration,
pub region: region::Configuration,
board_eirp: BoardEirp,
state: State,
}

struct BoardEirp {
max_power: u8,
antenna_gain: i8,
}

#[allow(clippy::large_enum_variant)]
enum State {
Joined(Session),
Expand All @@ -100,9 +107,10 @@ pub struct SendData<'a> {
pub(crate) type Result<T = ()> = core::result::Result<T, Error>;

impl Mac {
pub(crate) fn new(region: region::Configuration) -> Self {
pub(crate) fn new(region: region::Configuration, max_power: u8, antenna_gain: i8) -> Self {
let data_rate = region.get_default_datarate();
Self {
board_eirp: BoardEirp { max_power, antenna_gain },
region,
state: State::Unjoined,
configuration: Configuration {
Expand All @@ -125,7 +133,10 @@ impl Mac {
let mut otaa = otaa::Otaa::new(credentials);
let dev_nonce = otaa.prepare_buffer::<C, RNG, N>(rng, buf);
self.state = State::Otaa(otaa);
(self.region.create_tx_config(rng, self.configuration.data_rate, &Frame::Join), dev_nonce)
let mut tx_config =
self.region.create_tx_config(rng, self.configuration.data_rate, &Frame::Join);
tx_config.adjust_power(self.board_eirp.max_power, self.board_eirp.antenna_gain);
(tx_config, dev_nonce)
}

/// Join via ABP. This does not transmit a join request frame, but instead sets the session.
Expand Down Expand Up @@ -156,7 +167,10 @@ impl Mac {
State::Otaa(_) => Err(Error::NotJoined),
State::Unjoined => Err(Error::NotJoined),
}?;
Ok((self.region.create_tx_config(rng, self.configuration.data_rate, &Frame::Data), fcnt))
let mut tx_config =
self.region.create_tx_config(rng, self.configuration.data_rate, &Frame::Data);
tx_config.adjust_power(self.board_eirp.max_power, self.board_eirp.antenna_gain);
Ok((tx_config, fcnt))
}

pub(crate) fn get_rx_delay(&self, frame: &Frame, window: &Window) -> u32 {
Expand Down
4 changes: 2 additions & 2 deletions device/src/nb_device/mod.rs
Expand Up @@ -36,7 +36,7 @@ where
radio,
rng,
tx_buffer: RadioBuffer::new(),
mac: mac::Mac::new(region),
mac: Mac::new(region, R::MAX_RADIO_POWER, R::ANTENNA_GAIN),
downlink: None,
},
}
Expand Down Expand Up @@ -108,7 +108,7 @@ where
}
}

pub(crate) struct Shared<R: radio::PhyRxTx + Timings, RNG: RngCore, const N: usize> {
pub(crate) struct Shared<R: PhyRxTx + Timings, RNG: RngCore, const N: usize> {
pub(crate) radio: R,
pub(crate) rng: RNG,
pub(crate) tx_buffer: RadioBuffer<N>,
Expand Down
7 changes: 7 additions & 0 deletions device/src/nb_device/radio.rs
Expand Up @@ -33,6 +33,13 @@ pub trait PhyRxTx {
type PhyError: fmt::Debug;
type PhyResponse: fmt::Debug;

/// Board-specific antenna gain and power loss in dBi.
const ANTENNA_GAIN: i8 = 0;

/// Maximum power (dBm) that the radio is able to output. When preparing instructions for radio,
/// the value of maximum power will be used as an upper bound.
const MAX_RADIO_POWER: u8;

fn get_mut_radio(&mut self) -> &mut Self;

// we require mutability so we may decrypt in place
Expand Down
4 changes: 4 additions & 0 deletions device/src/nb_device/test/util.rs
Expand Up @@ -45,6 +45,10 @@ impl PhyRxTx for TestRadio {
type PhyError = &'static str;
type PhyResponse = ();

const MAX_RADIO_POWER: u8 = 26;

const ANTENNA_GAIN: i8 = 0;

fn get_mut_radio(&mut self) -> &mut Self {
self
}
Expand Down
7 changes: 7 additions & 0 deletions device/src/radio.rs
Expand Up @@ -14,6 +14,13 @@ pub struct TxConfig {
pub rf: RfConfig,
}

impl TxConfig {
pub fn adjust_power(&mut self, max_power: u8, antenna_gain: i8) {
self.pw -= antenna_gain;
self.pw = core::cmp::min(self.pw, max_power as i8);
}
}

#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RxQuality {
Expand Down

0 comments on commit 7dffe22

Please sign in to comment.