lorawan_device/nb_device/
mod.rs1use super::radio::RadioBuffer;
5use super::*;
6use crate::nb_device::radio::PhyRxTx;
7use mac::{Mac, SendData};
8
9pub(crate) mod state;
10
11pub mod radio;
12#[cfg(test)]
13mod test;
14
15type TimestampMs = u32;
16
17pub struct Device<R, C, RNG, const N: usize, const D: usize = 1>
18where
19 R: PhyRxTx + Timings,
20 C: CryptoFactory + Default,
21 RNG: RngCore,
22{
23 state: State,
24 shared: Shared<R, RNG, N, D>,
25 crypto: PhantomData<C>,
26}
27
28impl<R, C, RNG, const N: usize, const D: usize> Device<R, C, RNG, N, D>
29where
30 R: PhyRxTx + Timings,
31 C: CryptoFactory + Default,
32 RNG: RngCore,
33{
34 pub fn new(region: region::Configuration, radio: R, rng: RNG) -> Device<R, C, RNG, N, D> {
35 Device {
36 crypto: PhantomData,
37 state: State::default(),
38 shared: Shared {
39 radio,
40 rng,
41 tx_buffer: RadioBuffer::new(),
42 mac: Mac::new(region, R::MAX_RADIO_POWER, R::ANTENNA_GAIN),
43 downlink: Vec::new(),
44 },
45 }
46 }
47
48 pub fn join(&mut self, join_mode: JoinMode) -> Result<Response, Error<R>> {
49 match join_mode {
50 JoinMode::OTAA { deveui, appeui, appkey } => {
51 self.handle_event(Event::Join(NetworkCredentials::new(appeui, deveui, appkey)))
52 }
53 JoinMode::ABP { devaddr, appskey, newskey } => {
54 self.shared.mac.join_abp(newskey, appskey, devaddr);
55 Ok(Response::JoinSuccess)
56 }
57 }
58 }
59
60 pub fn get_radio(&mut self) -> &mut R {
61 &mut self.shared.radio
62 }
63
64 pub fn get_datarate(&mut self) -> region::DR {
65 self.shared.mac.configuration.data_rate
66 }
67
68 pub fn set_datarate(&mut self, datarate: region::DR) {
69 self.shared.mac.configuration.data_rate = datarate
70 }
71
72 pub fn ready_to_send_data(&self) -> bool {
73 matches!(&self.state, State::Idle(_)) && self.shared.mac.is_joined()
74 }
75
76 pub fn send(&mut self, data: &[u8], fport: u8, confirmed: bool) -> Result<Response, Error<R>> {
77 self.handle_event(Event::SendDataRequest(SendData { data, fport, confirmed }))
78 }
79
80 pub fn get_fcnt_up(&self) -> Option<u32> {
81 self.shared.mac.get_fcnt_up()
82 }
83
84 pub fn get_session(&self) -> Option<&mac::Session> {
85 self.shared.mac.get_session()
86 }
87
88 pub fn set_session(&mut self, s: mac::Session) {
89 self.shared.mac.set_session(s)
90 }
91
92 pub fn get_session_keys(&self) -> Option<mac::SessionKeys> {
93 self.shared.mac.get_session_keys()
94 }
95
96 pub fn take_downlink(&mut self) -> Option<Downlink> {
97 self.shared.downlink.pop()
98 }
99
100 pub fn handle_event(&mut self, event: Event<R>) -> Result<Response, Error<R>> {
101 let (new_state, result) = self.state.handle_event::<R, C, RNG, N, D>(
102 &mut self.shared.mac,
103 &mut self.shared.radio,
104 &mut self.shared.rng,
105 &mut self.shared.tx_buffer,
106 &mut self.shared.downlink,
107 event,
108 );
109 self.state = new_state;
110 result
111 }
112}
113
114pub(crate) struct Shared<R: PhyRxTx + Timings, RNG: RngCore, const N: usize, const D: usize> {
115 pub(crate) radio: R,
116 pub(crate) rng: RNG,
117 pub(crate) tx_buffer: RadioBuffer<N>,
118 pub(crate) mac: Mac,
119 pub(crate) downlink: Vec<Downlink, D>,
120}
121
122#[derive(Debug)]
123pub enum Response {
124 NoUpdate,
125 TimeoutRequest(TimestampMs),
126 JoinRequestSending,
127 JoinSuccess,
128 NoJoinAccept,
129 UplinkSending(mac::FcntUp),
130 DownlinkReceived(mac::FcntDown),
131 NoAck,
132 ReadyToSend,
133 SessionExpired,
134 RxComplete,
135}
136
137#[derive(Debug)]
138pub enum Error<R: PhyRxTx> {
139 Radio(R::PhyError),
140 State(state::Error),
141 Mac(mac::Error),
142}
143
144impl<R: PhyRxTx> From<mac::Error> for Error<R> {
145 fn from(mac_error: mac::Error) -> Error<R> {
146 Error::Mac(mac_error)
147 }
148}
149
150pub enum Event<'a, R>
151where
152 R: PhyRxTx,
153{
154 Join(NetworkCredentials),
155 SendDataRequest(SendData<'a>),
156 RadioEvent(radio::Event<'a, R>),
157 TimeoutFired,
158}
159
160impl<'a, R> core::fmt::Debug for Event<'a, R>
161where
162 R: PhyRxTx,
163{
164 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165 let event = match self {
166 Event::Join(_) => "Join",
167 Event::SendDataRequest(_) => "SendDataRequest",
168 Event::RadioEvent(_) => "RadioEvent",
169 Event::TimeoutFired => "TimeoutFired",
170 };
171 write!(f, "lorawan_device::Event::{event}")
172 }
173}