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