Compare commits
8 Commits
6943fffe26
...
36bdf9dd16
Author | SHA1 | Date |
---|---|---|
Leonora Tindall | 36bdf9dd16 | |
Leonora Tindall | acf059aa1a | |
Leonora Tindall | d42b0ec6b3 | |
Leonora Tindall | fa31aab5cf | |
Leonora Tindall | 12cce7213b | |
Leonora Tindall | 6318251226 | |
Leonora Tindall | dd2102d973 | |
Leonora Tindall | 84fa9e5e01 |
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -5,8 +5,28 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## Unreleased - v0.2.0
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- `Rn2903::system_version_bytes()`
|
||||||
|
- `Rn2903::system_factory_reset()`
|
||||||
|
- `Rn2903::system_module_reset()`
|
||||||
|
- `Rn2903::mac_pause()` and `::mac_resume()`
|
||||||
|
- `BadResponse` and `CannotPause` error variants
|
||||||
|
- Examples directory with LED blinky and LoRa packet RX examples
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- `main.rs` (moved to an example)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
## v0.1.0
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- GNU GPL v3 license
|
- GNU GPL v3 license
|
||||||
|
|
|
@ -17,3 +17,13 @@ CHANGELOG.md.
|
||||||
|
|
||||||
All method documentation is written in the present tense. For example, "Creates a new..."
|
All method documentation is written in the present tense. For example, "Creates a new..."
|
||||||
rather than "Create a new...".
|
rather than "Create a new...".
|
||||||
|
|
||||||
|
## Cutting a Release
|
||||||
|
|
||||||
|
When cutting a release:
|
||||||
|
|
||||||
|
- In CHANGELOG, rename the Unreleased section and add a new Unreleased section above it
|
||||||
|
- Make a commit with only that change
|
||||||
|
- Tag that commit like "v1.0.0"
|
||||||
|
- Push main and the tag
|
||||||
|
- `cargo publish`
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
use rn2903::Rn2903;
|
||||||
|
use std::env::args;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<_> = args().collect();
|
||||||
|
if args.len() <= 1 {
|
||||||
|
eprintln!("rn2903_blinky <serial port>");
|
||||||
|
eprintln!("\tReset the module and toggle pin 0b10 on and off.");
|
||||||
|
eprintln!("\tThis corresponds to the blue user LED on the LoStik.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut txvr = Rn2903::new_at(&args[1]).expect("Could not open device. Error");
|
||||||
|
println!(
|
||||||
|
"Successfully connected. Version: {}",
|
||||||
|
txvr.system_version()
|
||||||
|
.expect("Could not read from device. Error:")
|
||||||
|
);
|
||||||
|
|
||||||
|
txvr.system_module_reset().unwrap();
|
||||||
|
txvr.transact(b"mac pause").unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
txvr.transact(b"sys set pindig GPIO10 1").unwrap();
|
||||||
|
thread::sleep(Duration::from_millis(1000));
|
||||||
|
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
||||||
|
thread::sleep(Duration::from_millis(1000));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
use rn2903::Rn2903;
|
||||||
|
use std::env::args;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<_> = args().collect();
|
||||||
|
if args.len() <= 1 {
|
||||||
|
eprintln!("rn2903_lora_packet_rx <serial port>");
|
||||||
|
eprintln!("\tRecieve LoRa packets and print their corresponding hex values.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut txvr = Rn2903::new_at(&args[1]).expect("Could not open device. Error");
|
||||||
|
println!(
|
||||||
|
"Successfully connected. Version: {}",
|
||||||
|
txvr.system_version()
|
||||||
|
.expect("Could not read from device. Error:")
|
||||||
|
);
|
||||||
|
|
||||||
|
txvr.mac_pause().unwrap();
|
||||||
|
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
||||||
|
txvr.transact(b"radio rx 0").unwrap();
|
||||||
|
loop {
|
||||||
|
println!("{:?}", txvr.read_line().unwrap());
|
||||||
|
txvr.transact(b"sys set pindig GPIO10 1").unwrap();
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
txvr.transact(b"sys set pindig GPIO10 0").unwrap();
|
||||||
|
txvr.transact(b"radio rx 0").unwrap();
|
||||||
|
}
|
||||||
|
}
|
90
src/lib.rs
90
src/lib.rs
|
@ -36,6 +36,19 @@ quick_error! {
|
||||||
display("Could not verify version string. Expected a RN2903 firmware revision, got '{}'",
|
display("Could not verify version string. Expected a RN2903 firmware revision, got '{}'",
|
||||||
version)
|
version)
|
||||||
}
|
}
|
||||||
|
/// The device returned a response that doesn't make sense, given the command that
|
||||||
|
/// was issued.
|
||||||
|
BadResponse(expected: String, response: String) {
|
||||||
|
description("bad response from module")
|
||||||
|
display("Received a bad response from the module. Expected '{}', got '{}'.",
|
||||||
|
expected, response)
|
||||||
|
}
|
||||||
|
/// The device is operating in a mode which prevents MAC functionality from being
|
||||||
|
/// paused, but a pause was requested.
|
||||||
|
CannotPause {
|
||||||
|
description("the LoRaWAN MAC cannot be paused")
|
||||||
|
display("The LoRaWAN MAC cannot be paused right now, but a pause was requested.")
|
||||||
|
}
|
||||||
/// 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.
|
||||||
|
@ -47,6 +60,12 @@ quick_error! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
fn bad_response<S: Into<String>, T: Into<String>>(expected: S, response: T) -> Self {
|
||||||
|
Self::BadResponse(expected.into(), response.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Universal `Result` wrapper for the RN2903 interface.
|
/// Universal `Result` wrapper for the RN2903 interface.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
@ -133,9 +152,7 @@ pub struct Rn2903 {
|
||||||
/// # Meta (type) Functions
|
/// # Meta (type) Functions
|
||||||
///
|
///
|
||||||
/// These functions deal with the type `Rn2903`, providing ways to create and manipulate
|
/// These functions deal with the type `Rn2903`, providing ways to create and manipulate
|
||||||
/// the structure itself. Aside from performing validation of the device on the other side
|
/// the structure itself.
|
||||||
/// of the serial link, these functions do not communicate with the module.
|
|
||||||
///
|
|
||||||
/// ## Creating an `Rn2903`
|
/// ## Creating an `Rn2903`
|
||||||
/// There are several ways to create a `Rn2903` wrapper for an RN2903 serial connection.
|
/// There are several ways to create a `Rn2903` wrapper for an RN2903 serial connection.
|
||||||
/// `::new_at()` is the recommended method, but `::new()` can be useful if the platform
|
/// `::new_at()` is the recommended method, but `::new()` can be useful if the platform
|
||||||
|
@ -220,6 +237,21 @@ impl Rn2903 {
|
||||||
self.read_line()
|
self.read_line()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience function for situations where only one response is expected according
|
||||||
|
/// to the module's documentation. Receiving another response means something wacky
|
||||||
|
/// is going on.
|
||||||
|
fn transact_expecting(&mut self, command: &[u8], expectation: &[u8]) -> Result<()> {
|
||||||
|
let bytes = self.transact(command)?;
|
||||||
|
if bytes != expectation {
|
||||||
|
Err(Error::bad_response(
|
||||||
|
bytes_to_string(expectation),
|
||||||
|
bytes_to_string(&bytes),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes the specified command to the module, adding a CRLF and flushing the buffer.
|
/// Writes the specified command to the module, adding a CRLF and flushing the buffer.
|
||||||
///
|
///
|
||||||
/// Using [`::transact()`](#method.transact) is preferred.
|
/// Using [`::transact()`](#method.transact) is preferred.
|
||||||
|
@ -274,7 +306,6 @@ impl Rn2903 {
|
||||||
|
|
||||||
Ok(vec)
|
Ok(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # System API Functions
|
/// # System API Functions
|
||||||
|
@ -286,4 +317,55 @@ impl Rn2903 {
|
||||||
let bytes = self.transact(b"sys get ver")?;
|
let bytes = self.transact(b"sys get ver")?;
|
||||||
Ok(bytes_to_string(&bytes))
|
Ok(bytes_to_string(&bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queries the module for its firmware version information.
|
||||||
|
///
|
||||||
|
/// As `::system_version()`, but returns bytes.
|
||||||
|
pub fn system_version_bytes(&mut self) -> Result<Vec<u8>> {
|
||||||
|
self.transact(b"sys get ver")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets the CPU on the connected module. State in memory is lost and the MAC
|
||||||
|
/// starts up upon reboot, automatically loading default LoRaWAN settings.
|
||||||
|
///
|
||||||
|
/// Returns the system version, like `::system_version_bytes()`.
|
||||||
|
pub fn system_module_reset(&mut self) -> Result<Vec<u8>> {
|
||||||
|
self.transact(b"sys reset")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a factory reset on the connected module. All EEPROM values are
|
||||||
|
/// restored to factory defaults. All LoRaWAN settings set by the user are lost.
|
||||||
|
///
|
||||||
|
/// Returns the system version, like `::system_version_bytes()`.
|
||||||
|
pub fn system_factory_reset(&mut self) -> Result<Vec<u8>> {
|
||||||
|
self.transact(b"sys factoryRESET")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # MAC API Functions
|
||||||
|
impl Rn2903 {
|
||||||
|
/// Pauses the LoRaWAN MAC functionality on the device, returning the number of
|
||||||
|
/// milliseconds for which the MAC can remain paused without affecting LoRaWAN
|
||||||
|
/// functionality.
|
||||||
|
///
|
||||||
|
/// This command can fail with `CannotPause`, meaning the device is operating in a
|
||||||
|
/// mode (like LoRaWAN Class C mode) in which pausing the MAC for any period of time
|
||||||
|
/// would result in degraded service.
|
||||||
|
pub fn mac_pause(&mut self) -> Result<u32> {
|
||||||
|
let val = bytes_to_string(&self.transact(b"mac pause")?);
|
||||||
|
let ms: u32 = match val.parse() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => return Err(Error::bad_response("<integer>", val)),
|
||||||
|
};
|
||||||
|
if ms == 0 {
|
||||||
|
Err(Error::CannotPause)
|
||||||
|
} else {
|
||||||
|
Ok(ms)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resumes LoRaWAN MAC functionality on the device after being paused.
|
||||||
|
pub fn mac_resume(&mut self) -> Result<()> {
|
||||||
|
self.transact_expecting(b"mac resume", b"ok")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -1,17 +0,0 @@
|
||||||
use rn2903::{Rn2903, bytes_to_string};
|
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut txvr = Rn2903::new_at("/dev/ttyUSB0").expect("Could not open device. Error");
|
|
||||||
println!(
|
|
||||||
"Successfully connected. Version: {}",
|
|
||||||
txvr
|
|
||||||
.system_version()
|
|
||||||
.expect("Could not read from device. Error:")
|
|
||||||
);
|
|
||||||
|
|
||||||
dbg!(bytes_to_string(&txvr.transact(b"sys set pindig GPIO10 1").unwrap()));
|
|
||||||
thread::sleep(Duration::from_millis(200));
|
|
||||||
dbg!(bytes_to_string(&txvr.transact(b"sys set pindig GPIO10 0").unwrap()));
|
|
||||||
}
|
|
Loading…
Reference in New Issue