Add LoRa and FSK packet reception
Add a function to change the modulation mode and a function to receive packets. Still needs a ton of work on various radio features and no implementation of gfsk yet.
This commit is contained in:
parent
34dd0902f2
commit
ccb9b89908
|
@ -13,14 +13,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- `Rn2903::system_module_reset()`
|
- `Rn2903::system_module_reset()`
|
||||||
- `Rn2903::mac_pause()` and `::mac_resume()`
|
- `Rn2903::mac_pause()` and `::mac_resume()`
|
||||||
- `Rn2903::system_{get, set}_nvm()`
|
- `Rn2903::system_{get, set}_nvm()`
|
||||||
- `BadResponse` and `CannotPause` error variants
|
- `Rn2903::radio_set_modulation_mode()`
|
||||||
|
- `Rn2903::radio_rx()`
|
||||||
|
- `BadResponse`, `TransceiverBusy`, and `CannotPause` error variants
|
||||||
- `NvmAddress` newtype for representing values that can be passed to NVM functions
|
- `NvmAddress` newtype for representing values that can be passed to NVM functions
|
||||||
|
- `ModulationMode` enum listing available modulation modes
|
||||||
- Examples directory:
|
- Examples directory:
|
||||||
- LED blink
|
- LED blink
|
||||||
- NVM read/write
|
- NVM read/write
|
||||||
- LoRa packet RX
|
- LoRa packet RX
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- README.md example (now showing packet RX)
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
|
|
16
README.md
16
README.md
|
@ -13,22 +13,20 @@ not directly depend on unstable crates.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
For instance, here is a simple program which blinks the LoStik's LED using the RN2903's
|
For instance, here is a simple program which dumps all LoRa packets received.
|
||||||
GPIO functionality.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rn2903::Rn2903;
|
use rn2903::{Rn2903, ModulationMode};
|
||||||
use std::time::Duration;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut txvr = Rn2903::new_at("/dev/ttyUSB0")
|
let mut txvr = Rn2903::new_at("/dev/ttyUSB0")
|
||||||
.expect("Could not open device. Error");
|
.expect("Could not open device. Error");
|
||||||
|
txvr.mac_pause().unwrap();
|
||||||
|
txvr.radio_set_modulation_mode(ModulationMode::LoRa).unwrap();
|
||||||
loop {
|
loop {
|
||||||
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
if let Some(packet) = txvr.radio_rx(65535).unwrap() {
|
||||||
thread::sleep(Duration::from_millis(1000));
|
println!("{:?}", packet);
|
||||||
txvr.transact(b"sys set pindig GPIO10 1").unwrap();
|
}
|
||||||
thread::sleep(Duration::from_millis(1000));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use rn2903::Rn2903;
|
use rn2903::{bytes_to_string, Rn2903};
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -21,12 +21,12 @@ fn main() {
|
||||||
|
|
||||||
txvr.mac_pause().unwrap();
|
txvr.mac_pause().unwrap();
|
||||||
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
||||||
txvr.transact(b"radio rx 0").unwrap();
|
|
||||||
loop {
|
loop {
|
||||||
println!("{:?}", txvr.read_line().unwrap());
|
if let Some(packet) = txvr.radio_rx(65535).unwrap() {
|
||||||
|
println!("{:?}", packet);
|
||||||
txvr.transact(b"sys set pindig GPIO10 1").unwrap();
|
txvr.transact(b"sys set pindig GPIO10 1").unwrap();
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
||||||
txvr.transact(b"radio rx 0").unwrap();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
77
src/lib.rs
77
src/lib.rs
|
@ -8,6 +8,23 @@
|
||||||
//! TTY or virtual COM port, or a RN2903 connected via a TTL serial interface.
|
//! TTY or virtual COM port, or a RN2903 connected via a TTL serial interface.
|
||||||
//!
|
//!
|
||||||
//! See the [`Rn2903` struct](struct.Rn2903.html) for the bulk of the crate's functionality.
|
//! See the [`Rn2903` struct](struct.Rn2903.html) for the bulk of the crate's functionality.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! Receiving and printing valid LoRa payloads.
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! # use rn2903::{Rn2903, ModulationMode};
|
||||||
|
//! let mut txvr = Rn2903::new_at("/dev/ttyUSB0")
|
||||||
|
//! .expect("Could not open device. Error");
|
||||||
|
//! txvr.mac_pause().unwrap();
|
||||||
|
//! txvr.radio_set_modulation_mode(ModulationMode::LoRa).unwrap();
|
||||||
|
//! loop {
|
||||||
|
//! if let Some(packet) = txvr.radio_rx(65535).unwrap() {
|
||||||
|
//! println!("{:?}", packet);
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
// One of the critical aspects of this library is error handling. Because it is intended
|
// One of the critical aspects of this library is error handling. Because it is intended
|
||||||
// to communicate with an external device, any operation could discover a disconnection
|
// to communicate with an external device, any operation could discover a disconnection
|
||||||
|
@ -49,6 +66,12 @@ quick_error! {
|
||||||
description("the LoRaWAN MAC cannot be paused")
|
description("the LoRaWAN MAC cannot be paused")
|
||||||
display("The LoRaWAN MAC cannot be paused right now, but a pause was requested.")
|
display("The LoRaWAN MAC cannot be paused right now, but a pause was requested.")
|
||||||
}
|
}
|
||||||
|
/// The transceiver is busy with another operation, or is under the control of
|
||||||
|
/// the MAC, and cannot be used to perform the requested operation.
|
||||||
|
TransceiverBusy {
|
||||||
|
description("the radio transceiver hardware is in use")
|
||||||
|
display("The LoRa/FSK radio transceiver hardware is in use by another operation or the MAC layer and cannot be used to perform the requested operation.")
|
||||||
|
}
|
||||||
/// The program has become disconnected from the RN2903 module due to an I/O
|
/// The program has become disconnected from the RN2903 module due to an I/O
|
||||||
/// error. It is possible the device was physically disconnected, or that the
|
/// error. It is possible the device was physically disconnected, or that the
|
||||||
/// host operating system closed the serial port for some reason.
|
/// host operating system closed the serial port for some reason.
|
||||||
|
@ -390,6 +413,60 @@ impl Rn2903 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Types of modulation available for transmitting and receiving packets.
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum ModulationMode {
|
||||||
|
/// Regular digital frequency shift keying mode
|
||||||
|
Fsk,
|
||||||
|
/// LoRa chirp spread spectrum mode
|
||||||
|
LoRa, // TODO: GFSK with radio set bt <value>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Radio API Functions
|
||||||
|
impl Rn2903 {
|
||||||
|
/// Set the modulation mode used by the radio for transmission and reception.
|
||||||
|
pub fn radio_set_modulation_mode(&mut self, mode: ModulationMode) -> Result<()> {
|
||||||
|
match mode {
|
||||||
|
ModulationMode::Fsk => self.transact_expecting(b"radio set mod fsk", b"ok"),
|
||||||
|
ModulationMode::LoRa => self.transact_expecting(b"radio set mod lora", b"ok"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open the receiver for the given timeout in symbols (for LoRa) or milliseconds
|
||||||
|
/// (for FSK), returning `Ok(Some(_))` if a valid packet is received or `Ok(None)` if
|
||||||
|
/// no packet is received before the timeout.
|
||||||
|
pub fn radio_rx(&mut self, timeout: u16) -> Result<Option<Vec<u8>>> {
|
||||||
|
let result = self.transact(&format!("radio rx {}", timeout).into_bytes())?;
|
||||||
|
match &result[..] {
|
||||||
|
b"ok" => (),
|
||||||
|
b"busy" => return Err(Error::TransceiverBusy),
|
||||||
|
v => return Err(Error::bad_response("ok | busy", bytes_to_string(v))),
|
||||||
|
};
|
||||||
|
let response = self.read_line()?;
|
||||||
|
match &response[0..9] {
|
||||||
|
b"radio_err" => Ok(None),
|
||||||
|
b"radio_rx " => {
|
||||||
|
let response_bytes: std::result::Result<Vec<u8>, _> = response[10..]
|
||||||
|
.chunks(2)
|
||||||
|
.map(bytes_to_string)
|
||||||
|
.map(|b| u8::from_str_radix(&b, 16))
|
||||||
|
.collect();
|
||||||
|
match response_bytes {
|
||||||
|
Ok(v) => Ok(Some(v)),
|
||||||
|
Err(_) => Err(Error::bad_response(
|
||||||
|
"radio_rx <bytes>",
|
||||||
|
bytes_to_string(&response),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(Error::bad_response(
|
||||||
|
"radio_err | radio_rx <bytes>",
|
||||||
|
bytes_to_string(&response),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// # MAC API Functions
|
/// # MAC API Functions
|
||||||
impl Rn2903 {
|
impl Rn2903 {
|
||||||
/// Pauses the LoRaWAN MAC functionality on the device, returning the number of
|
/// Pauses the LoRaWAN MAC functionality on the device, returning the number of
|
||||||
|
|
Loading…
Reference in New Issue