Skip to content

Commit

Permalink
create BoardEirp trait
Browse files Browse the repository at this point in the history
  • Loading branch information
lthiery committed Nov 5, 2023
1 parent 5193c00 commit bebd047
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 47 deletions.
26 changes: 15 additions & 11 deletions device/src/async_device/mod.rs
Expand Up @@ -3,18 +3,19 @@
use super::mac::Mac;

use super::mac::{self, Frame, Window};
pub use super::{
pub use crate::{
mac::{NetworkCredentials, SendData, Session},
region::{self, Region},
Downlink, JoinMode, Timings,
BoardEirp, DefaultBoardEirp, Downlink, JoinMode, Timings,
};
use crate::{radio::RadioBuffer, rng};
use core::marker::PhantomData;
use futures::{future::select, future::Either, pin_mut};
use lorawan::{self, keys::CryptoFactory};
use rand_core::RngCore;

pub use crate::region::DR;
use crate::{radio::RadioBuffer, rng};

#[cfg(feature = "external-lora-phy")]
/// provide the radio through the external lora-phy crate
pub mod lora_radio;
Expand All @@ -34,18 +35,19 @@ use core::cmp::min;
/// - C: A CryptoFactory implementation
/// - RNG: A random number generator implementation. An external RNG may be provided, or you may use a builtin PRNG by
/// providing a random seed.
pub struct Device<R, C, T, G, const N: usize = 256>
pub struct Device<R, C, T, G, B = DefaultBoardEirp, const N: usize = 256>
where
R: radio::PhyRxTx + Timings,
T: radio::Timer,
C: CryptoFactory + Default,
T: radio::Timer,
G: RngCore,
B: BoardEirp,
{
crypto: PhantomData<C>,
radio: R,
rng: G,
crypto: PhantomData<C>,
timer: T,
mac: Mac,
rng: G,
mac: Mac<B>,
radio_buffer: RadioBuffer<N>,
downlink: Option<Downlink>,
}
Expand Down Expand Up @@ -83,11 +85,12 @@ enum RxWindowResponse<F: futures::Future<Output = ()> + Sized + Unpin> {
Timeout(u32),
}

impl<R, C, T, const N: usize> Device<R, C, T, rng::Prng, N>
impl<R, C, T, B, const N: usize> Device<R, C, T, rng::Prng, B, N>
where
R: radio::PhyRxTx + Timings,
C: CryptoFactory + Default,
T: radio::Timer,
B: BoardEirp + Default,
{
/// Create a new [`Device`] by providing your own random seed. Using this method, [`Device`] will internally
/// use an algorithmic PRNG. Depending on your use case, this may or may not be faster than using your own
Expand Down Expand Up @@ -123,12 +126,13 @@ where
}
}

impl<R, C, T, G, const N: usize> Device<R, C, T, G, N>
impl<R, C, T, G, B, const N: usize> Device<R, C, T, G, B, N>
where
R: radio::PhyRxTx + Timings,
C: CryptoFactory + Default,
T: radio::Timer,
G: RngCore,
B: BoardEirp + Default,
{
/// Create a new instance of [`Device`] with a RNG external to the LoRa chip. You must provide your own RNG
/// implementing [`RngCore`].
Expand All @@ -147,7 +151,7 @@ where
rng: G,
session: Option<Session>,
) -> Self {
let mut mac = Mac::new(region);
let mut mac = Mac::new(region, B::default());
if let Some(session) = session {
mac.set_session(session);
}
Expand Down
10 changes: 8 additions & 2 deletions device/src/async_device/test/mod.rs
Expand Up @@ -17,8 +17,14 @@ use radio::TestRadio;
mod util;
use util::{setup, setup_with_session};

type Device =
crate::async_device::Device<TestRadio, DefaultFactory, TestTimer, rand_core::OsRng, 512>;
type Device = crate::async_device::Device<
TestRadio,
DefaultFactory,
TestTimer,
rand_core::OsRng,
DefaultBoardEirp,
512,
>;

#[tokio::test]
async fn test_join_rx1() {
Expand Down
5 changes: 4 additions & 1 deletion device/src/async_device/test/util.rs
@@ -1,4 +1,6 @@
use super::{get_dev_addr, get_key, radio::*, region, timer::*, DefaultFactory, Device};
use super::{
get_dev_addr, get_key, radio::*, region, timer::*, DefaultBoardEirp, DefaultFactory, Device,
};

use crate::mac::Session;
use crate::{AppSKey, NewSKey};
Expand All @@ -12,6 +14,7 @@ fn setup_internal(session_data: Option<Session>) -> (RadioChannel, TimerChannel,
DefaultFactory,
TestTimer,
rand_core::OsRng,
DefaultBoardEirp,
512,
> = Device::new_with_session(
region.into(),
Expand Down
21 changes: 21 additions & 0 deletions device/src/lib.rs
Expand Up @@ -54,6 +54,27 @@ pub trait Timings {
fn get_rx_window_duration_ms(&self) -> u32;
}

pub trait BoardEirp {
/// Returns the antenna gain in dBi. You should take into account any board losses here.
fn get_antenna_gain(&self) -> u8;

/// The max power the radio can be instructed to transmit at. When preparing an instruction
/// for the radio, this max power will be used an upper bound.
fn max_radio_power(&self) -> u8;
}

#[derive(Default)]
pub struct DefaultBoardEirp;
impl BoardEirp for DefaultBoardEirp {
fn get_antenna_gain(&self) -> u8 {
0
}

fn max_radio_power(&self) -> u8 {
26
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum JoinMode {
Expand Down
33 changes: 27 additions & 6 deletions device/src/mac/mod.rs
@@ -1,6 +1,6 @@
use crate::{
radio::{self, RadioBuffer},
region, AppSKey, Downlink, NewSKey,
region, AppSKey, BoardEirp, Downlink, NewSKey,
};
use lorawan::parser::DevAddr;
use lorawan::{self, keys::CryptoFactory, maccommands::MacCommand};
Expand Down Expand Up @@ -71,9 +71,13 @@ impl Configuration {
}
}

pub(crate) struct Mac {
pub(crate) struct Mac<B>
where
B: BoardEirp,
{
pub configuration: Configuration,
pub region: region::Configuration,
board_eirp: B,
state: State,
}

Expand All @@ -99,12 +103,13 @@ pub struct SendData<'a> {

pub(crate) type Result<T = ()> = core::result::Result<T, Error>;

impl Mac {
pub(crate) fn new(region: region::Configuration) -> Self {
impl<B: BoardEirp> Mac<B> {
pub(crate) fn new(region: region::Configuration, board_eirp: B) -> Self {
let data_rate = region.get_default_datarate();
Self {
region,
state: State::Unjoined,
board_eirp,
configuration: Configuration {
data_rate,
rx1_delay: region::constants::RECEIVE_DELAY1,
Expand All @@ -125,7 +130,15 @@ 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)
(
self.region.create_tx_config(
&self.board_eirp,
rng,
self.configuration.data_rate,
&Frame::Join,
),
dev_nonce,
)
}

/// Join via ABP. This does not transmit a join request frame, but instead sets the session.
Expand Down Expand Up @@ -156,7 +169,15 @@ 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))
Ok((
self.region.create_tx_config(
&self.board_eirp,
rng,
self.configuration.data_rate,
&Frame::Data,
),
fcnt,
))
}

pub(crate) fn get_rx_delay(&self, frame: &Frame, window: &Window) -> u32 {
Expand Down
25 changes: 16 additions & 9 deletions device/src/nb_device/mod.rs
Expand Up @@ -11,32 +11,34 @@ mod test;

type TimestampMs = u32;

pub struct Device<R, C, RNG, const N: usize>
pub struct Device<R, C, RNG, B = DefaultBoardEirp, const N: usize = 255>
where
R: radio::PhyRxTx + Timings,
R: PhyRxTx + Timings,
C: CryptoFactory + Default,
RNG: RngCore,
B: BoardEirp,
{
state: State,
shared: Shared<R, RNG, N>,
shared: Shared<R, RNG, B, N>,
crypto: PhantomData<C>,
}

impl<R, C, RNG, const N: usize> Device<R, C, RNG, N>
impl<R, C, RNG, B, const N: usize> Device<R, C, RNG, B, N>
where
R: PhyRxTx + Timings,
C: CryptoFactory + Default,
RNG: RngCore,
B: BoardEirp + Default,
{
pub fn new(region: region::Configuration, radio: R, rng: RNG) -> Device<R, C, RNG, N> {
pub fn new(region: region::Configuration, radio: R, rng: RNG) -> Device<R, C, RNG, B, N> {
Device {
crypto: PhantomData,
state: State::default(),
shared: Shared {
radio,
rng,
tx_buffer: RadioBuffer::new(),
mac: mac::Mac::new(region),
mac: Mac::new(region, B::default()),
downlink: None,
},
}
Expand Down Expand Up @@ -95,7 +97,7 @@ where
}

pub fn handle_event(&mut self, event: Event<R>) -> Result<Response, Error<R>> {
let (new_state, result) = self.state.handle_event::<R, C, RNG, N>(
let (new_state, result) = self.state.handle_event::<R, C, RNG, B, N>(
&mut self.shared.mac,
&mut self.shared.radio,
&mut self.shared.rng,
Expand All @@ -108,11 +110,16 @@ where
}
}

pub(crate) struct Shared<R: radio::PhyRxTx + Timings, RNG: RngCore, const N: usize> {
pub(crate) struct Shared<
R: PhyRxTx + Timings,
RNG: RngCore,
B: BoardEirp = DefaultBoardEirp,
const N: usize = 255,
> {
pub(crate) radio: R,
pub(crate) rng: RNG,
pub(crate) tx_buffer: RadioBuffer<N>,
pub(crate) mac: Mac,
pub(crate) mac: Mac<B>,
pub(crate) downlink: Option<Downlink>,
}

Expand Down
33 changes: 18 additions & 15 deletions device/src/nb_device/state.rs
Expand Up @@ -105,21 +105,22 @@ impl State {
R: radio::PhyRxTx + Timings,
C: CryptoFactory + Default,
RNG: RngCore,
B: BoardEirp,
const N: usize,
>(
self,
mac: &mut Mac,
mac: &mut Mac<B>,
radio: &mut R,
rng: &mut RNG,
buf: &mut RadioBuffer<N>,
dl: &mut Option<Downlink>,
event: Event<R>,
) -> (Self, Result<Response, super::Error<R>>) {
match self {
State::Idle(s) => s.handle_event::<R, C, RNG, N>(mac, radio, rng, buf, event),
State::SendingData(s) => s.handle_event::<R, N>(mac, radio, event),
State::WaitingForRxWindow(s) => s.handle_event::<R, N>(mac, radio, event),
State::WaitingForRx(s) => s.handle_event::<R, C, N>(mac, radio, buf, event, dl),
State::Idle(s) => s.handle_event::<R, C, RNG, B, N>(mac, radio, rng, buf, event),
State::SendingData(s) => s.handle_event::<R, B, N>(mac, radio, event),
State::WaitingForRxWindow(s) => s.handle_event::<R, B, N>(mac, radio, event),
State::WaitingForRx(s) => s.handle_event::<R, C, B, N>(mac, radio, buf, event, dl),
}
}
}
Expand All @@ -132,10 +133,11 @@ impl Idle {
R: radio::PhyRxTx + Timings,
C: CryptoFactory + Default,
RNG: RngCore,
B: BoardEirp,
const N: usize,
>(
self,
mac: &mut Mac,
mac: &mut Mac<B>,
radio: &mut R,
rng: &mut RNG,
buf: &mut RadioBuffer<N>,
Expand Down Expand Up @@ -183,7 +185,7 @@ impl Idle {
// directly jump to waiting for RxWindow
// allows for synchronous sending
radio::Response::TxDone(ms) => {
data_rxwindow1_timeout::<R, N>(frame, mac, radio, ms)
data_rxwindow1_timeout::<R, B, N>(frame, mac, radio, ms)
}
_ => (State::Idle(self), Err(Error::UnexpectedRadioResponse.into())),
}
Expand All @@ -201,9 +203,9 @@ pub struct SendingData {
}

impl SendingData {
pub(crate) fn handle_event<R: radio::PhyRxTx + Timings, const N: usize>(
pub(crate) fn handle_event<R: radio::PhyRxTx + Timings, B: BoardEirp, const N: usize>(
self,
mac: &mut Mac,
mac: &mut Mac<B>,
radio: &mut R,
event: Event<R>,
) -> (State, Result<Response, super::Error<R>>) {
Expand All @@ -216,7 +218,7 @@ impl SendingData {
match response {
// expect a complete transmit
radio::Response::TxDone(ms) => {
data_rxwindow1_timeout::<R, N>(self.frame, mac, radio, ms)
data_rxwindow1_timeout::<R, B, N>(self.frame, mac, radio, ms)
}
// anything other than TxComplete is unexpected
_ => {
Expand Down Expand Up @@ -244,9 +246,9 @@ pub struct WaitingForRxWindow {
}

impl WaitingForRxWindow {
pub(crate) fn handle_event<R: radio::PhyRxTx + Timings, const N: usize>(
pub(crate) fn handle_event<R: radio::PhyRxTx + Timings, B: BoardEirp, const N: usize>(
self,
mac: &mut Mac,
mac: &mut Mac<B>,
radio: &mut R,
event: Event<R>,
) -> (State, Result<Response, super::Error<R>>) {
Expand Down Expand Up @@ -312,10 +314,11 @@ impl WaitingForRx {
pub(crate) fn handle_event<
R: radio::PhyRxTx + Timings,
C: CryptoFactory + Default,
B: BoardEirp,
const N: usize,
>(
self,
mac: &mut Mac,
mac: &mut Mac<B>,
radio: &mut R,
buf: &mut RadioBuffer<N>,
event: Event<R>,
Expand Down Expand Up @@ -394,9 +397,9 @@ enum Rx {
_2(u32),
}

fn data_rxwindow1_timeout<R: radio::PhyRxTx + Timings, const N: usize>(
fn data_rxwindow1_timeout<R: radio::PhyRxTx + Timings, B: BoardEirp, const N: usize>(
frame: Frame,
mac: &mut Mac,
mac: &mut Mac<B>,
radio: &mut R,
timestamp_ms: u32,
) -> (State, Result<Response, super::Error<R>>) {
Expand Down

0 comments on commit bebd047

Please sign in to comment.