Skip to main content

drogue_rak811/
lib.rs

1#![no_std]
2//!A network driver for a RAK811 attached via a UART.
3//!
4//!Currently requires the RAK811 to be flashed with a 2.x version of the AT firmware.
5//!
6//!At first, the UART must be configured and handed to the driver. The uart must implement the `embedded_hal::serial` traits.
7//!
8//!## Usage
9//!
10//!```rust
11//!let (uarte_tx, uarte_rx) = uarte
12//!    .split(ctx.resources.tx_buf, ctx.resources.rx_buf)
13//!    .unwrap();
14//!
15//!
16//!let driver = rak811::Rak811Driver::new(
17//!    uarte_tx,
18//!    uarte_rx,
19//!    port1.p1_02.into_push_pull_output(Level::High).degrade(),
20//!)
21//!.unwrap();
22//!```
23//!
24//!In order to connect to the gateway, the LoRa node needs to be configured with the following:
25//!
26//!* Frequency band - This depends on where you live.
27//!* Mode of operation - This can either be LoRa P2P which allows the node to send and receive data directly from another LoRa node, or LoRaWAN which connects the node to a gateway.
28//!
29//!The driver can be used to configure the properties in this way:
30//!
31//!```rust
32//!driver.set_band(rak811::LoraRegion::EU868).unwrap();
33//!driver.set_mode(rak811::LoraMode::WAN).unwrap();
34//!```
35//!
36//!In addition, the following settings from the TTN console must be set:
37//!
38//!* Device EUI
39//!* Application EUI
40//!* Application Key
41//!
42//!```rust
43//!driver.set_device_eui(&[0x00, 0xBB, 0x7C, 0x95, 0xAD, 0xB5, 0x30, 0xB9]).unwrap();
44//!driver.set_app_eui(&[0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x03, 0xB1, 0x84])
45//!
46//!// Secret generated by network provider
47//!driver .set_app_key(&[0x00]).unwrap();
48//!```
49//!
50//!To join the network and send packets:
51//!
52//!```rust
53//!driver.join(rak811::ConnectMode::OTAA).unwrap();
54//!
55//!// Port number can be between 1 and 255
56//!driver.send(rak811::QoS::Confirmed, 1, b"hello!").unwrap();
57//!```
58
59use embedded_hal::digital::v2::OutputPin;
60use embedded_hal::{serial::Read, serial::Write};
61mod buffer;
62mod error;
63mod parser;
64mod protocol;
65
66use buffer::*;
67pub use error::*;
68use heapless::consts;
69use heapless::spsc::Queue;
70pub use protocol::*;
71
72const RECV_BUFFER_LEN: usize = 256;
73
74pub struct Rak811Driver<W, R, RST>
75where
76    W: Write<u8>,
77    R: Read<u8>,
78    RST: OutputPin,
79{
80    tx: W,
81    rx: R,
82    parse_buffer: Buffer,
83    rxq: Queue<Response, consts::U4>,
84    connect_mode: ConnectMode,
85    lora_mode: LoraMode,
86    lora_band: LoraRegion,
87    rst: RST,
88}
89
90impl<W, R, RST> Rak811Driver<W, R, RST>
91where
92    W: Write<u8>,
93    R: Read<u8>,
94    RST: OutputPin,
95{
96    /// Create a new instance of the driver. The driver will trigger a reset of the module
97    /// and expect a response from the firmware.
98    pub fn new(tx: W, rx: R, rst: RST) -> Result<Rak811Driver<W, R, RST>, DriverError> {
99        let mut driver = Rak811Driver {
100            tx,
101            rx,
102            rst,
103            parse_buffer: Buffer::new(),
104            connect_mode: ConnectMode::OTAA,
105            lora_mode: LoraMode::WAN,
106            lora_band: LoraRegion::EU868,
107            rxq: Queue::new(),
108        };
109
110        driver.initialize()?;
111        Ok(driver)
112    }
113
114    /// Initialize the driver. This will cause the RAK811 module to be reset.
115    pub fn initialize(&mut self) -> Result<(), DriverError> {
116        self.rst.set_high().ok();
117        self.rst.set_low().ok();
118        let response = self.recv_response()?;
119        match response {
120            Response::Initialized => Ok(()),
121            _ => Err(DriverError::NotInitialized),
122        }
123    }
124
125    /// Send reset command to lora module. Depending on the mode, this will restart
126    /// the module or reload its configuration from EEPROM.
127    pub fn reset(&mut self, mode: ResetMode) -> Result<(), DriverError> {
128        let response = self.send_command(Command::Reset(mode))?;
129        match response {
130            Response::Ok => {
131                let response = self.recv_response()?;
132                match response {
133                    Response::Initialized => Ok(()),
134                    _ => Err(DriverError::NotInitialized),
135                }
136            }
137            r => Err(DriverError::UnexpectedResponse(r)),
138        }
139    }
140
141    /// Join a LoRa Network using the specified mode.
142    pub fn join(&mut self, mode: ConnectMode) -> Result<(), DriverError> {
143        self.connect_mode = mode;
144        let response = self.send_command(Command::Join(mode))?;
145        match response {
146            Response::Ok => {
147                let response = self.recv_response()?;
148                match response {
149                    Response::Recv(EventCode::JoinedSuccess, _, _, _) => Ok(()),
150                    r => Err(DriverError::UnexpectedResponse(r)),
151                }
152            }
153            r => Err(DriverError::UnexpectedResponse(r)),
154        }
155    }
156
157    /// Set the frequency band based on the region.
158    pub fn set_band(&mut self, band: LoraRegion) -> Result<(), DriverError> {
159        self.lora_band = band;
160        let response = self.send_command(Command::SetBand(band))?;
161        match response {
162            Response::Ok => Ok(()),
163            r => Err(DriverError::UnexpectedResponse(r)),
164        }
165    }
166
167    /// Set the mode of operation, peer to peer or network mode.
168    pub fn set_mode(&mut self, mode: LoraMode) -> Result<(), DriverError> {
169        self.lora_mode = mode;
170        let response = self.send_command(Command::SetMode(mode))?;
171        match response {
172            Response::Ok => Ok(()),
173            r => Err(DriverError::UnexpectedResponse(r)),
174        }
175    }
176
177    pub fn set_device_address(&mut self, addr: &DevAddr) -> Result<(), DriverError> {
178        let response = self.send_command(Command::SetConfig(ConfigOption::DevAddr(addr)))?;
179        match response {
180            Response::Ok => Ok(()),
181            r => Err(DriverError::UnexpectedResponse(r)),
182        }
183    }
184    pub fn set_device_eui(&mut self, eui: &EUI) -> Result<(), DriverError> {
185        let response = self.send_command(Command::SetConfig(ConfigOption::DevEui(eui)))?;
186        match response {
187            Response::Ok => Ok(()),
188            r => Err(DriverError::UnexpectedResponse(r)),
189        }
190    }
191    pub fn set_app_eui(&mut self, eui: &EUI) -> Result<(), DriverError> {
192        let response = self.send_command(Command::SetConfig(ConfigOption::AppEui(eui)))?;
193        match response {
194            Response::Ok => Ok(()),
195            r => Err(DriverError::UnexpectedResponse(r)),
196        }
197    }
198
199    pub fn set_app_key(&mut self, key: &AppKey) -> Result<(), DriverError> {
200        let response = self.send_command(Command::SetConfig(ConfigOption::AppKey(key)))?;
201        match response {
202            Response::Ok => Ok(()),
203            r => Err(DriverError::UnexpectedResponse(r)),
204        }
205    }
206
207    /// Transmit data using the specified confirmation mode and given port.
208    pub fn send(&mut self, qos: QoS, port: Port, data: &[u8]) -> Result<(), DriverError> {
209        let response = self.send_command(Command::Send(qos, port, data))?;
210        match response {
211            Response::Ok => {
212                let response = self.recv_response()?;
213                let expected_code = match qos {
214                    QoS::Unconfirmed => EventCode::TxUnconfirmed,
215                    QoS::Confirmed => EventCode::TxConfirmed,
216                };
217                match response {
218                    Response::Recv(c, 0, _, _) if expected_code == c => Ok(()),
219                    r => Err(DriverError::UnexpectedResponse(r)),
220                }
221            }
222            r => Err(DriverError::UnexpectedResponse(r)),
223        }
224    }
225
226    /// Poll for any received data and copy it to the provided buffer. If data have been received,
227    /// the length of the data is returned.
228    pub fn try_recv(&mut self, port: Port, rx_buf: &mut [u8]) -> Result<usize, DriverError> {
229        self.digest()?;
230        let mut tries = self.rxq.len();
231        while tries > 0 {
232            match self.rxq.dequeue() {
233                None => return Ok(0),
234                Some(Response::Recv(EventCode::RecvData, p, len, Some(data))) if p == port => {
235                    if len > rx_buf.len() {
236                        self.rxq
237                            .enqueue(Response::Recv(EventCode::RecvData, p, len, Some(data)))
238                            .map_err(|_| DriverError::ReadError)?;
239                    }
240
241                    rx_buf[0..len].clone_from_slice(&data);
242                    return Ok(len);
243                }
244                Some(event) => {
245                    self.rxq
246                        .enqueue(event)
247                        .map_err(|_| DriverError::ReadError)?;
248                }
249            }
250            tries -= 1;
251        }
252        Ok(0)
253    }
254
255    /// Attempt to read data from UART and store it in the parse buffer. This should
256    /// be invoked whenever data should be read.
257    pub fn process(&mut self) -> Result<(), DriverError> {
258        loop {
259            match self.rx.read() {
260                Err(nb::Error::WouldBlock) => {
261                    break;
262                }
263                Err(nb::Error::Other(_)) => return Err(DriverError::ReadError),
264                Ok(b) => {
265                    self.parse_buffer
266                        .write(b)
267                        .map_err(|_| DriverError::ReadError)?;
268                }
269            }
270        }
271        Ok(())
272    }
273
274    /// Attempt to parse the internal buffer and enqueue any response data found.
275    pub fn digest(&mut self) -> Result<(), DriverError> {
276        let result = self.parse_buffer.parse();
277        if let Ok(response) = result {
278            if !matches!(response, Response::None) {
279                log::debug!("Got response: {:?}", response);
280                self.rxq
281                    .enqueue(response)
282                    .map_err(|_| DriverError::ReadError)?;
283            }
284        }
285        Ok(())
286    }
287
288    // Block until a response is received.
289    fn recv_response(&mut self) -> Result<Response, DriverError> {
290        loop {
291            // Run processing to increase likelyhood we have something to parse.
292            for _ in 0..1000 {
293                self.process()?;
294            }
295            self.digest()?;
296            if let Some(response) = self.rxq.dequeue() {
297                return Ok(response);
298            }
299        }
300    }
301
302    fn do_write(&mut self, buf: &[u8]) -> Result<(), DriverError> {
303        for b in buf.iter() {
304            match self.tx.write(*b) {
305                Err(nb::Error::WouldBlock) => {
306                    nb::block!(self.tx.flush()).map_err(|_| DriverError::WriteError)?;
307                }
308                Err(_) => return Err(DriverError::WriteError),
309                _ => {}
310            }
311        }
312        nb::block!(self.tx.flush()).map_err(|_| DriverError::WriteError)?;
313        Ok(())
314    }
315
316    /// Send an AT command to the lora module and await a response.
317    pub fn send_command(&mut self, command: Command) -> Result<Response, DriverError> {
318        let mut s = Command::buffer();
319        command.encode(&mut s);
320        log::debug!("Sending command {}", s.as_str());
321        self.do_write(s.as_bytes())?;
322        self.do_write(b"\r\n")?;
323
324        let response = self.recv_response()?;
325        Ok(response)
326    }
327}
328
329#[cfg(test)]
330mod tests {
331    #[test]
332    fn it_works() {
333        assert_eq!(2 + 2, 4);
334    }
335}