From 34dd0902f2459042b943c01b0d8f7d51757b0a0a Mon Sep 17 00:00:00 2001 From: Leonora Tindall Date: Tue, 31 Dec 2019 17:01:39 -0800 Subject: [PATCH] Add NVM read/write functions Including adding a wrapper type for NVM addresses to provide validation that the wrong addresses aren't being sent to the device --- CHANGELOG.md | 7 +++++- examples/nvm_set_get.rs | 45 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 48 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 examples/nvm_set_get.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3a890..2f59291 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Rn2903::system_factory_reset()` - `Rn2903::system_module_reset()` - `Rn2903::mac_pause()` and `::mac_resume()` +- `Rn2903::system_{get, set}_nvm()` - `BadResponse` and `CannotPause` error variants -- Examples directory with LED blinky and LoRa packet RX examples +- `NvmAddress` newtype for representing values that can be passed to NVM functions +- Examples directory: + - LED blink + - NVM read/write + - LoRa packet RX ### Changed diff --git a/examples/nvm_set_get.rs b/examples/nvm_set_get.rs new file mode 100644 index 0000000..bbd3a94 --- /dev/null +++ b/examples/nvm_set_get.rs @@ -0,0 +1,45 @@ +use rn2903::{NvmAddress, 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_nvm_set_get "); + eprintln!("\tGet, modify, check, and restore the contents of NVM::0x300."); + 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(); + let addr = NvmAddress::new(0x300); + + txvr.transact(b"sys set pindig GPIO10 1").unwrap(); + let prev = txvr.system_get_nvm(addr).unwrap(); + println!("Previous value: {:#x}", prev); + txvr.transact(b"sys set pindig GPIO10 0").unwrap(); + + txvr.transact(b"sys set pindig GPIO11 1").unwrap(); + txvr.system_set_nvm(addr, 0xAB).unwrap(); + println!("Wrote new value"); + txvr.transact(b"sys set pindig GPIO11 0").unwrap(); + + txvr.transact(b"sys set pindig GPIO10 1").unwrap(); + let new = txvr.system_get_nvm(addr).unwrap(); + println!("New value: {:#x}", new); + txvr.transact(b"sys set pindig GPIO10 0").unwrap(); + + txvr.transact(b"sys set pindig GPIO11 1").unwrap(); + txvr.system_set_nvm(addr, prev).unwrap(); + println!("Restored old value"); + txvr.transact(b"sys set pindig GPIO11 0").unwrap(); +} diff --git a/src/lib.rs b/src/lib.rs index cd6ca63..4153461 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -308,6 +308,34 @@ impl Rn2903 { } } +/// An address in user-accessible nonvolatile memory. Guaranteed to be between 0x300 and +/// 0x3FF. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct NvmAddress(u16); + +impl NvmAddress { + /// Create a new `NvmAddress` from a `u16`. The given value must be between 0x300 and + /// 0x3FF. + /// + /// # Panics + /// Panics if the given value is not between 0x300 and 0x3FF. + pub fn new(value: u16) -> NvmAddress { + if value < 0x300 { + panic!("Attempted to construct NvmAddress less than 0x300."); + } + if value > 0x3FF { + panic!("Attempted to construct NvmAddress more than 0x3FF."); + } + NvmAddress(value) + } + + /// Return the address to which this NvmAddress refers. Guaranteed to be between + /// 0x300 and 0x3FF. + pub fn inner(self) -> u16 { + self.0 + } +} + /// # System API Functions impl Rn2903 { /// Queries the module for its firmware version information. @@ -340,6 +368,26 @@ impl Rn2903 { pub fn system_factory_reset(&mut self) -> Result> { self.transact(b"sys factoryRESET") } + + /// Set the value of the on-MCU nonvolatile memory at the given address to the given + /// value. + pub fn system_set_nvm(&mut self, address: NvmAddress, value: u8) -> Result<()> { + self.transact_expecting( + &format!("sys set nvm {:x} {:x}", address.inner(), value).into_bytes(), + b"ok", + ) + } + + /// Get the value of the on-MCU nonvolatile memory at the given address. + pub fn system_get_nvm(&mut self, address: NvmAddress) -> Result { + let response = bytes_to_string( + &self.transact(&format!("sys get nvm {:x}", address.inner()).into_bytes())?, + ); + match u8::from_str_radix(&response, 16) { + Ok(v) => Ok(v), + Err(_) => Err(Error::bad_response("", response)), + } + } } /// # MAC API Functions