#![cfg_attr(not(test), no_std)]
pub mod errors;
mod utils;
use core::convert::TryFrom;
use core::marker::PhantomData;
use core::str::{from_utf8, FromStr};
use core::time::Duration;
use doc_comment::doc_comment;
use embedded_hal::serial;
use nb::block;
use numtoa::NumToA;
#[cfg(feature = "logging")]
use core::fmt;
#[cfg(feature = "logging")]
use log;
use crate::errors::{Error, JoinError, RnResult, TxError};
const CR: u8 = 0x0d;
const LF: u8 = 0x0a;
pub trait Frequency {}
pub struct Freq433;
pub struct Freq868;
pub struct Freq915;
impl Frequency for Freq433 {}
impl Frequency for Freq868 {}
impl Frequency for Freq915 {}
#[cfg(feature = "logging")]
struct LoggableStrSlice<'o, 'i>(&'o [&'i str]);
#[cfg(feature = "logging")]
impl fmt::Display for LoggableStrSlice<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for part in self.0 {
write!(f, "{}", part)?;
}
Ok(())
}
}
pub struct Driver<F: Frequency, S> {
frequency: PhantomData<F>,
serial: S,
read_buf: [u8; 64],
sleep: bool,
}
#[derive(Debug, PartialEq, Eq)]
pub enum Model {
RN2483,
RN2903,
}
#[derive(Debug, PartialEq, Eq)]
pub enum JoinMode {
Otaa,
Abp,
}
#[derive(Debug, PartialEq, Eq)]
pub enum ConfirmationMode {
Confirmed,
Unconfirmed,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum DataRateEuCn {
Sf12Bw125,
Sf11Bw125,
Sf10Bw125,
Sf9Bw125,
Sf8Bw125,
Sf7Bw125,
Sf7Bw250,
}
impl From<DataRateEuCn> for &str {
fn from(dr: DataRateEuCn) -> Self {
match dr {
DataRateEuCn::Sf12Bw125 => "0",
DataRateEuCn::Sf11Bw125 => "1",
DataRateEuCn::Sf10Bw125 => "2",
DataRateEuCn::Sf9Bw125 => "3",
DataRateEuCn::Sf8Bw125 => "4",
DataRateEuCn::Sf7Bw125 => "5",
DataRateEuCn::Sf7Bw250 => "6",
}
}
}
impl TryFrom<&str> for DataRateEuCn {
type Error = Error;
fn try_from(val: &str) -> Result<Self, Self::Error> {
match val {
"0" => Ok(DataRateEuCn::Sf12Bw125),
"1" => Ok(DataRateEuCn::Sf11Bw125),
"2" => Ok(DataRateEuCn::Sf10Bw125),
"3" => Ok(DataRateEuCn::Sf9Bw125),
"4" => Ok(DataRateEuCn::Sf8Bw125),
"5" => Ok(DataRateEuCn::Sf7Bw125),
"6" => Ok(DataRateEuCn::Sf7Bw250),
_ => Err(Error::ParsingError),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum DataRateUs {
Sf10Bw125,
Sf9Bw125,
Sf8Bw125,
Sf7Bw125,
Sf8Bw500,
}
impl From<DataRateUs> for &str {
fn from(dr: DataRateUs) -> Self {
match dr {
DataRateUs::Sf10Bw125 => "0",
DataRateUs::Sf9Bw125 => "1",
DataRateUs::Sf8Bw125 => "2",
DataRateUs::Sf7Bw125 => "3",
DataRateUs::Sf8Bw500 => "4",
}
}
}
impl TryFrom<&str> for DataRateUs {
type Error = Error;
fn try_from(val: &str) -> Result<Self, Self::Error> {
match val {
"0" => Ok(DataRateUs::Sf10Bw125),
"1" => Ok(DataRateUs::Sf9Bw125),
"2" => Ok(DataRateUs::Sf8Bw125),
"3" => Ok(DataRateUs::Sf7Bw125),
"4" => Ok(DataRateUs::Sf8Bw500),
_ => Err(Error::ParsingError),
}
}
}
#[derive(Debug, PartialEq)]
pub struct Downlink<'a> {
port: u8,
hexdata: &'a str,
}
pub fn rn2483_433<S, E>(serial: S) -> Driver<Freq433, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
{
Driver {
frequency: PhantomData,
serial,
read_buf: [0; 64],
sleep: false,
}
}
pub fn rn2483_868<S, E>(serial: S) -> Driver<Freq868, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
{
Driver {
frequency: PhantomData,
serial,
read_buf: [0; 64],
sleep: false,
}
}
pub fn rn2903_915<S, E>(serial: S) -> Driver<Freq915, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
{
Driver {
frequency: PhantomData,
serial,
read_buf: [0; 64],
sleep: false,
}
}
impl<F, S, E> Driver<F, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
F: Frequency,
{
fn write_byte(&mut self, byte: u8) -> RnResult<()> {
block!(self.serial.write(byte)).map_err(|_| Error::SerialWrite)
}
fn ensure_not_in_sleep_mode(&self) -> RnResult<()> {
if self.sleep {
Err(Error::SleepMode)
} else {
Ok(())
}
}
fn write_crlf(&mut self) -> RnResult<()> {
self.ensure_not_in_sleep_mode()?;
self.write_byte(CR)?;
self.write_byte(LF)
}
fn write_all(&mut self, buffer: &[u8]) -> RnResult<()> {
self.ensure_not_in_sleep_mode()?;
for byte in buffer {
self.write_byte(*byte)?;
}
Ok(())
}
fn read_byte(&mut self) -> RnResult<u8> {
block!(self.serial.read()).map_err(|_| Error::SerialRead)
}
pub fn read_line(&mut self) -> RnResult<&[u8]> {
let buflen = self.read_buf.len();
let mut i = 0;
loop {
match self.read_byte()? {
LF if self.read_buf[i - 1] == CR => {
#[cfg(feature = "logging")]
log::debug!(
"Received response: {:?}",
from_utf8(&self.read_buf[0..(i - 1)]).unwrap_or("\"[invalid-utf8]\"")
);
return Ok(&self.read_buf[0..(i - 1)]);
}
other => {
self.read_buf[i] = other;
}
}
i += 1;
if i >= buflen {
return Err(Error::ReadBufferTooSmall);
}
}
}
pub fn send_raw_command_nowait(&mut self, command: &[&str]) -> RnResult<()> {
#[cfg(feature = "logging")]
log::debug!("Sending command: \"{}\"", LoggableStrSlice(command));
for part in command {
self.write_all(part.as_bytes())?;
}
self.write_crlf()?;
Ok(())
}
pub fn send_raw_command(&mut self, command: &[&str]) -> RnResult<&[u8]> {
self.send_raw_command_nowait(command)?;
self.read_line()
}
pub fn send_raw_command_str(&mut self, command: &[&str]) -> RnResult<&str> {
let bytes = self.send_raw_command(command)?;
Ok(from_utf8(bytes)?)
}
fn send_raw_command_ok(&mut self, command: &[&str]) -> RnResult<()> {
let response = self.send_raw_command(command)?;
if response == b"ok" {
Ok(())
} else {
Err(Error::CommandFailed)
}
}
pub fn ensure_known_state(&mut self) -> RnResult<()> {
loop {
match self.serial.read() {
Ok(_) => {
#[cfg(feature = "logging")]
log::debug!("Clearing input buffer: Discarded 1 byte");
}
Err(nb::Error::WouldBlock) => break,
Err(nb::Error::Other(_)) => return Err(Error::SerialRead),
}
}
#[cfg(feature = "logging")]
log::debug!("Input buffer is clear");
for _ in 0..3 {
#[cfg(feature = "logging")]
log::debug!("Check whether module is in a known state, expecting \"invalid_param\"");
self.write_byte(b'z')?;
self.write_crlf()?;
match self.read_line()? {
b"invalid_param" => return Ok(()),
_other => {
#[cfg(feature = "logging")]
log::debug!("Error: Module returned \"{:?}\"", _other);
}
}
}
Err(Error::InvalidState)
}
}
impl<F, S, E> Driver<F, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
F: Frequency,
{
pub fn free(self) -> S {
self.serial
}
pub fn reset(&mut self) -> RnResult<&str> {
self.send_raw_command_str(&["sys reset"])
}
pub fn factory_reset(&mut self) -> RnResult<&str> {
self.send_raw_command_str(&["sys factoryRESET"])
}
pub fn hweui(&mut self) -> RnResult<&str> {
self.send_raw_command_str(&["sys get hweui"])
}
pub fn version(&mut self) -> RnResult<&str> {
self.send_raw_command_str(&["sys get ver"])
}
pub fn model(&mut self) -> RnResult<Model> {
let version = self.version()?;
match &version[0..6] {
"RN2483" => Ok(Model::RN2483),
"RN2903" => Ok(Model::RN2903),
_ => Err(Error::ParsingError),
}
}
pub fn vdd(&mut self) -> RnResult<u16> {
let vdd = self.send_raw_command_str(&["sys get vdd"])?;
vdd.parse().map_err(|_| Error::ParsingError)
}
pub fn nvm_set(&mut self, addr: u16, byte: u8) -> RnResult<()> {
if addr < 0x300 || addr > 0x3ff {
return Err(Error::BadParameter);
}
let mut hex_addr_buf = [0; 4];
let addr_buf_byte_count = base16::encode_config_slice(
&addr.to_be_bytes(),
base16::EncodeLower,
&mut hex_addr_buf,
);
let hex_addr = from_utf8(&hex_addr_buf[..addr_buf_byte_count]).unwrap();
let hex_byte_bytes = base16::encode_byte_l(byte);
let hex_byte = from_utf8(&hex_byte_bytes).unwrap();
let args = ["sys set nvm ", utils::ltrim_hex(&hex_addr), " ", &hex_byte];
self.send_raw_command_ok(&args)
}
pub fn nvm_get(&mut self, addr: u16) -> RnResult<u8> {
if addr < 0x300 || addr > 0x3ff {
return Err(Error::BadParameter);
}
let mut hex_addr_buf = [0; 4];
let addr_buf_byte_count = base16::encode_config_slice(
&addr.to_be_bytes(),
base16::EncodeLower,
&mut hex_addr_buf,
);
let hex_addr = from_utf8(&hex_addr_buf[..addr_buf_byte_count]).unwrap();
let response = self.send_raw_command(&["sys get nvm ", utils::ltrim_hex(&hex_addr)])?;
if response.len() != 2 {
return Err(Error::ParsingError);
}
let mut buf = [0; 1];
base16::decode_slice(response, &mut buf).map_err(|_| Error::ParsingError)?;
Ok(buf[0])
}
pub fn sleep(&mut self, duration: Duration) -> RnResult<()> {
let secs: u64 = duration.as_secs();
let subsec_millis: u32 = duration.subsec_millis();
let millis: u32 = if secs == 0 && subsec_millis < 100 {
return Err(Error::BadParameter);
} else if (secs < 4_294_967) || (secs == 4_294_967 && subsec_millis <= 295) {
(secs * 1000) as u32 + duration.subsec_millis()
} else {
return Err(Error::BadParameter);
};
let mut buf = [0u8; 10];
self.send_raw_command_nowait(&["sys sleep ", millis.numtoa_str(10, &mut buf)])?;
self.sleep = true;
Ok(())
}
pub fn wait_for_wakeup(&mut self, force: bool) -> RnResult<()> {
if !force && !self.sleep {
return Ok(());
}
match self.read_line()? {
b"ok" => {
self.sleep = false;
Ok(())
}
_ => {
self.sleep = false;
Err(Error::ParsingError)
}
}
}
}
macro_rules! hex_setter_getter {
(
$field:expr, $bytes:expr, $descr:expr,
$set_hex:ident, $set_slice:ident
) => {
doc_comment! {
concat!(
"Set ",
$descr,
".",
"\n\nThe parameter must be a ", stringify!($bytes), "-byte hex string, ",
"otherwise `Error::BadParameter` will be returned.",
),
pub fn $set_hex(&mut self, val: &str) -> RnResult<()> {
if val.len() != $bytes * 2 {
return Err(Error::BadParameter);
}
self.send_raw_command_ok(&[concat!("mac set ", $field, " "), val])
}
}
doc_comment! {
concat!(
"Set ",
$descr,
".",
"\n\nThe parameter must be a ", stringify!($bytes), "-byte ",
"big endian byte slice, otherwise `Error::BadParameter` will be returned.",
),
pub fn $set_slice(&mut self, val: &[u8]) -> RnResult<()> {
if val.len() != $bytes {
return Err(Error::BadParameter);
}
let mut buf = [0; $bytes * 2];
base16::encode_config_slice(val, base16::EncodeLower, &mut buf);
self.$set_hex(from_utf8(&buf)?)
}
}
};
(
$field:expr, $bytes:expr, $descr:expr,
$set_hex:ident, $set_slice:ident,
$get_hex:ident, $get_slice:ident,
$(,)?
) => {
hex_setter_getter!($field, $bytes, $descr, $set_hex, $set_slice);
doc_comment! {
concat!("Get ", $descr, " as hex str."),
pub fn $get_hex(&mut self) -> RnResult<&str> {
self.send_raw_command_str(&[concat!("mac get ", $field)])
}
}
doc_comment! {
concat!("Get ", $descr, " bytes."),
pub fn $get_slice(&mut self) -> RnResult<[u8; $bytes]> {
let hex = self.$get_hex()?;
let mut buf = [0; $bytes];
base16::decode_slice(hex, &mut buf).map_err(|_| Error::ParsingError)?;
Ok(buf)
}
}
};
($field:expr, $bytes:expr, $descr:expr, $set_hex:ident, $set_slice:ident,) => {
hex_setter_getter!($field, $bytes, $descr, $set_hex, $set_slice);
};
($field:expr, $bytes:expr, $descr:expr, $set_hex:ident, $set_slice:ident, $get_hex:ident, $get_slice:ident,) => {
hex_setter_getter!($field, $bytes, $descr, $set_hex, $set_slice, $get_hex, $get_slice);
};
}
impl<F, S, E> Driver<F, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
F: Frequency,
{
pub fn save_config(&mut self) -> RnResult<()> {
self.send_raw_command_ok(&["mac save"])
}
hex_setter_getter!(
"devaddr",
4,
"the unique network device address",
set_dev_addr_hex,
set_dev_addr_slice,
get_dev_addr_hex,
get_dev_addr_slice,
);
hex_setter_getter!(
"deveui",
8,
"the globally unique device identifier",
set_dev_eui_hex,
set_dev_eui_slice,
get_dev_eui_hex,
get_dev_eui_slice,
);
hex_setter_getter!(
"appeui",
8,
"the globally unique application identifier",
set_app_eui_hex,
set_app_eui_slice,
get_app_eui_hex,
get_app_eui_slice,
);
hex_setter_getter!(
"nwkskey",
16,
"the network session key",
set_network_session_key_hex,
set_network_session_key_slice,
);
hex_setter_getter!(
"appskey",
16,
"the application session key",
set_app_session_key_hex,
set_app_session_key_slice,
);
hex_setter_getter!(
"appkey",
16,
"the application key",
set_app_key_hex,
set_app_key_slice,
);
pub fn set_adr(&mut self, enabled: bool) -> RnResult<()> {
let state = if enabled { "on" } else { "off" };
self.send_raw_command_ok(&["mac set adr ", state])
}
pub fn get_adr(&mut self) -> RnResult<bool> {
match self.send_raw_command_str(&["mac get adr"])? {
"on" => Ok(true),
"off" => Ok(false),
_ => Err(Error::ParsingError),
}
}
pub fn join(&mut self, mode: JoinMode) -> Result<(), JoinError> {
let mode_str = match mode {
JoinMode::Otaa => "otaa",
JoinMode::Abp => "abp",
};
match self.send_raw_command_str(&["mac join ", mode_str])? {
"ok" => {}
"invalid_param" => return Err(JoinError::BadParameter),
"keys_not_init" => return Err(JoinError::KeysNotInit),
"no_free_ch" => return Err(JoinError::NoFreeChannel),
"silent" => return Err(JoinError::Silent),
"busy" => return Err(JoinError::Busy),
"mac_paused" => return Err(JoinError::MacPaused),
"denied" => return Err(JoinError::JoinUnsuccessful),
_ => return Err(JoinError::UnknownResponse),
};
match self.read_line()? {
b"denied" => Err(JoinError::JoinUnsuccessful),
b"accepted" => Ok(()),
_ => Err(JoinError::UnknownResponse),
}
}
pub fn transmit_hex(
&mut self,
mode: ConfirmationMode,
port: u8,
data: &str,
) -> Result<Option<Downlink>, TxError> {
if data.len() % 2 != 0 {
return Err(TxError::BadParameter);
}
utils::validate_port(port, TxError::BadParameter)?;
let mode_str = match mode {
ConfirmationMode::Confirmed => "cnf",
ConfirmationMode::Unconfirmed => "uncnf",
};
let mut buf = [0; 3];
let port_str = utils::u8_to_str(port, &mut buf)?;
match self.send_raw_command(&["mac tx ", mode_str, " ", port_str, " ", data])? {
b"ok" => {}
b"invalid_param" => return Err(TxError::BadParameter),
b"not_joined" => return Err(TxError::NotJoined),
b"no_free_ch" => return Err(TxError::NoFreeChannel),
b"silent" => return Err(TxError::Silent),
b"frame_counter_err_rejoin_needed" => return Err(TxError::FrameCounterRollover),
b"busy" => return Err(TxError::Busy),
b"mac_paused" => return Err(TxError::MacPaused),
b"invalid_data_len" => return Err(TxError::InvalidDataLenth),
_ => return Err(TxError::UnknownResponse),
};
match self.read_line()? {
b"mac_tx_ok" => Ok(None),
b"mac_err" => Err(TxError::TxUnsuccessful),
b"invalid_data_len" => Err(TxError::InvalidDataLenth),
val if val.starts_with(b"mac_rx ") => {
let mut parts = from_utf8(val)?.split_ascii_whitespace();
let _ = parts.next().ok_or(TxError::Other(Error::ParsingError))?;
let port_str = parts.next().ok_or(TxError::Other(Error::ParsingError))?;
let port =
u8::from_str(&port_str).map_err(|_| TxError::Other(Error::ParsingError))?;
utils::validate_port(port, TxError::Other(Error::ParsingError))?;
let hexdata = parts.next().ok_or(TxError::Other(Error::ParsingError))?;
if hexdata.len() % 2 != 0 {
return Err(TxError::Other(Error::ParsingError));
}
Ok(Some(Downlink { port, hexdata }))
}
_ => Err(TxError::UnknownResponse),
}
}
pub fn transmit_slice(
&mut self,
mode: ConfirmationMode,
port: u8,
data: &[u8],
) -> Result<Option<Downlink>, TxError> {
let mut buf = [0; 256];
let bytes = base16::encode_config_slice(data, base16::EncodeLower, &mut buf);
self.transmit_hex(mode, port, from_utf8(&buf[0..bytes])?)
}
}
impl<S, E> Driver<Freq433, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
{
pub fn set_data_rate(&mut self, data_rate: DataRateEuCn) -> RnResult<()> {
self.send_raw_command_ok(&["mac set dr ", data_rate.into()])
}
pub fn get_data_rate(&mut self) -> RnResult<DataRateEuCn> {
let dr = self.send_raw_command_str(&["mac get dr"])?;
DataRateEuCn::try_from(dr)
}
}
impl<S, E> Driver<Freq868, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
{
pub fn set_data_rate(&mut self, data_rate: DataRateEuCn) -> RnResult<()> {
self.send_raw_command_ok(&["mac set dr ", data_rate.into()])
}
pub fn get_data_rate(&mut self) -> RnResult<DataRateEuCn> {
let dr = self.send_raw_command_str(&["mac get dr"])?;
DataRateEuCn::try_from(dr)
}
}
impl<S, E> Driver<Freq915, S>
where
S: serial::Read<u8, Error = E> + serial::Write<u8, Error = E>,
{
pub fn set_data_rate(&mut self, data_rate: DataRateUs) -> RnResult<()> {
self.send_raw_command_ok(&["mac set dr ", data_rate.into()])
}
pub fn get_data_rate(&mut self) -> RnResult<DataRateUs> {
let dr = self.send_raw_command_str(&["mac get dr"])?;
DataRateUs::try_from(dr)
}
}
#[cfg(test)]
mod tests {
use super::*;
use embedded_hal_mock::serial::{Mock as SerialMock, Transaction};
use embedded_hal_mock::MockError;
const VERSION48: &str = "RN2483 1.0.3 Mar 22 2017 06:00:42";
const VERSION90: &str = "RN2903 1.0.3 Mar 22 2017 06:00:42";
const CRLF: &str = "\r\n";
#[test]
fn version() {
let expectations = [
Transaction::write_many(b"sys get ver\r\n"),
Transaction::read_many(VERSION48.as_bytes()),
Transaction::read_many(CRLF.as_bytes()),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.version().unwrap(), VERSION48);
mock.done();
}
#[test]
fn model_rn2483() {
let expectations = [
Transaction::write_many(b"sys get ver\r\n"),
Transaction::read_many(VERSION48.as_bytes()),
Transaction::read_many(CRLF.as_bytes()),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.model().unwrap(), Model::RN2483);
mock.done();
}
#[test]
fn model_rn2903() {
let expectations = [
Transaction::write_many(b"sys get ver\r\n"),
Transaction::read_many(VERSION90.as_bytes()),
Transaction::read_many(CRLF.as_bytes()),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.model().unwrap(), Model::RN2903);
mock.done();
}
#[test]
fn nvm_set() {
let expectations = [
Transaction::write_many(b"sys set nvm 3ab 2a\r\n"),
Transaction::read_many(b"ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
rn.nvm_set(0x3ab, 42).unwrap();
mock.done();
}
#[test]
fn nvm_get() {
let expectations = [
Transaction::write_many(b"sys get nvm 300\r\n"),
Transaction::read_many(b"ff\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.nvm_get(0x300).unwrap(), 0xff);
mock.done();
}
#[test]
fn set_dev_addr_bad_length() {
let expectations = [];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.set_dev_addr_hex("010203f"), Err(Error::BadParameter));
assert_eq!(rn.set_dev_addr_hex("010203fff"), Err(Error::BadParameter));
assert_eq!(
rn.set_dev_eui_hex("0004a30b001a55e"),
Err(Error::BadParameter)
);
assert_eq!(
rn.set_dev_eui_hex("0004a30b001a55edx"),
Err(Error::BadParameter)
);
mock.done();
}
fn _set_dev_addr() -> (SerialMock<u8>, Driver<Freq868, SerialMock<u8>>) {
let expectations = [
Transaction::write_many(b"mac set devaddr 010203ff\r\n"),
Transaction::read_many(b"ok\r\n"),
];
let mock = SerialMock::new(&expectations);
let rn = rn2483_868(mock.clone());
(mock, rn)
}
#[test]
fn set_dev_addr_hex() {
let (mut mock, mut rn) = _set_dev_addr();
assert!(rn.set_dev_addr_hex("010203ff").is_ok());
mock.done();
}
#[test]
fn set_dev_addr_slice() {
let (mut mock, mut rn) = _set_dev_addr();
assert!(rn.set_dev_addr_slice(&[0x01, 0x02, 0x03, 0xff]).is_ok());
mock.done();
}
fn _set_dev_eui() -> (SerialMock<u8>, Driver<Freq868, SerialMock<u8>>) {
let expectations = [
Transaction::write_many(b"mac set deveui 0004a30b001a55ed\r\n".as_ref()),
Transaction::read_many(b"ok\r\n"),
];
let mock = SerialMock::new(&expectations);
let rn = rn2483_868(mock.clone());
(mock, rn)
}
#[test]
fn set_dev_eui_hex() {
let (mut mock, mut rn) = _set_dev_eui();
assert!(rn.set_dev_eui_hex("0004a30b001a55ed").is_ok());
mock.done();
}
#[test]
fn set_dev_eui_slice() {
let (mut mock, mut rn) = _set_dev_eui();
assert!(rn
.set_dev_eui_slice(&[0x00, 0x04, 0xa3, 0x0b, 0x00, 0x1a, 0x55, 0xed])
.is_ok());
mock.done();
}
fn _get_dev_eui() -> (SerialMock<u8>, Driver<Freq868, SerialMock<u8>>) {
let expectations = [
Transaction::write_many(b"mac get deveui\r\n".as_ref()),
Transaction::read_many(b"0004a30b001a55ed\r\n"),
];
let mock = SerialMock::new(&expectations);
let rn = rn2483_868(mock.clone());
(mock, rn)
}
#[test]
fn get_dev_eui_hex() {
let (mut mock, mut rn) = _get_dev_eui();
let deveui = rn.get_dev_eui_hex().unwrap();
assert_eq!(deveui, "0004a30b001a55ed");
mock.done();
}
#[test]
fn get_dev_eui_slice() {
let (mut mock, mut rn) = _get_dev_eui();
let deveui = rn.get_dev_eui_slice().unwrap();
assert_eq!(deveui, [0x00, 0x04, 0xa3, 0x0b, 0x00, 0x1a, 0x55, 0xed]);
mock.done();
}
mod data_rate {
use super::*;
#[test]
fn set_sf9_eucn() {
let expectations = [
Transaction::write_many(b"mac set dr 3\r\n"),
Transaction::read_many(b"ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert!(rn.set_data_rate(DataRateEuCn::Sf9Bw125).is_ok());
mock.done();
}
#[test]
fn set_sf9_us() {
let expectations = [
Transaction::write_many(b"mac set dr 1\r\n"),
Transaction::read_many(b"ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2903_915(mock.clone());
assert!(rn.set_data_rate(DataRateUs::Sf9Bw125).is_ok());
mock.done();
}
#[test]
fn set_sf12_eucn() {
let expectations = [
Transaction::write_many(b"mac set dr 0\r\n"),
Transaction::read_many(b"ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert!(rn.set_data_rate(DataRateEuCn::Sf12Bw125).is_ok());
mock.done();
}
#[test]
fn get_sf7_us() {
let expectations = [
Transaction::write_many(b"mac get dr\r\n"),
Transaction::read_many(b"4\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2903_915(mock.clone());
assert_eq!(rn.get_data_rate().unwrap(), DataRateUs::Sf8Bw500);
mock.done();
}
}
mod adr {
use super::*;
#[test]
fn get_on() {
let expectations = [
Transaction::write_many(b"mac get adr\r\n"),
Transaction::read_many(b"on\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert!(rn.get_adr().unwrap());
mock.done();
}
#[test]
fn get_off() {
let expectations = [
Transaction::write_many(b"mac get adr\r\n"),
Transaction::read_many(b"off\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert!(!rn.get_adr().unwrap());
mock.done();
}
#[test]
fn get_invalid() {
let expectations = [
Transaction::write_many(b"mac get adr\r\n"),
Transaction::read_many(b"of\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.get_adr().unwrap_err(), Error::ParsingError);
mock.done();
}
#[test]
fn set() {
let expectations = [
Transaction::write_many(b"mac set adr on\r\n"),
Transaction::read_many(b"ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert!(rn.set_adr(true).is_ok());
mock.done();
}
}
mod sleep {
use super::*;
#[test]
fn sleep_min_max_duration() {
let expectations = [Transaction::write_many(b"sys sleep 100\r\n")];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert!(rn.sleep(Duration::from_millis(100)).is_ok());
mock.done();
let expectations = [Transaction::write_many(b"sys sleep 4294967295\r\n")];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert!(rn.sleep(Duration::from_millis((1 << 32) - 1)).is_ok());
mock.done();
}
#[test]
fn sleep_invalid_durations() {
let expectations = [];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.sleep(Duration::from_millis(0)), Err(Error::BadParameter));
assert_eq!(
rn.sleep(Duration::from_millis(99)),
Err(Error::BadParameter)
);
assert_eq!(
rn.sleep(Duration::from_millis(1 << 32)),
Err(Error::BadParameter)
);
mock.done();
}
#[test]
fn sleep_mode_no_write() {
let expectations = [Transaction::write_many(b"sys sleep 1000\r\n")];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
rn.sleep(Duration::from_secs(1)).unwrap();
assert_eq!(rn.write_all(b"123"), Err(Error::SleepMode));
assert_eq!(rn.write_crlf(), Err(Error::SleepMode));
mock.done();
}
#[test]
fn wait_for_wakeup_immediate() {
let expectations = [];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.wait_for_wakeup(false), Ok(()));
assert_eq!(rn.wait_for_wakeup(false), Ok(()));
assert_eq!(rn.wait_for_wakeup(false), Ok(()));
mock.done();
let expectations = [Transaction::read_many(b"ok\r\n")];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.wait_for_wakeup(true), Ok(()));
mock.done();
}
#[test]
fn wait_for_wakeup_errors() {
let expectations = [Transaction::read_many(b"ohno\r\n")];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
rn.sleep = true;
assert_eq!(rn.wait_for_wakeup(false), Err(Error::ParsingError));
assert!(!rn.sleep);
mock.done();
}
}
mod join {
use super::*;
#[test]
fn otaa_ok() {
let expectations = [
Transaction::write_many(b"mac join otaa\r\n"),
Transaction::read_many(b"ok\r\naccepted\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.join(JoinMode::Otaa), Ok(()));
mock.done();
}
#[test]
fn abp_ok() {
let expectations = [
Transaction::write_many(b"mac join abp\r\n"),
Transaction::read_many(b"ok\r\naccepted\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.join(JoinMode::Abp), Ok(()));
mock.done();
}
#[test]
fn otaa_denied() {
let expectations = [
Transaction::write_many(b"mac join otaa\r\n"),
Transaction::read_many(b"ok\r\ndenied\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.join(JoinMode::Otaa), Err(JoinError::JoinUnsuccessful));
mock.done();
}
#[test]
fn otaa_unknown_response_1() {
let expectations = [
Transaction::write_many(b"mac join otaa\r\n"),
Transaction::read_many(b"xyz\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.join(JoinMode::Otaa), Err(JoinError::UnknownResponse));
mock.done();
}
#[test]
fn otaa_unknown_response_2() {
let expectations = [
Transaction::write_many(b"mac join otaa\r\n"),
Transaction::read_many(b"ok\r\nxyz\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.join(JoinMode::Otaa), Err(JoinError::UnknownResponse));
mock.done();
}
#[test]
fn otaa_no_free_ch() {
let expectations = [
Transaction::write_many(b"mac join otaa\r\n"),
Transaction::read_many(b"no_free_ch\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.join(JoinMode::Otaa), Err(JoinError::NoFreeChannel));
mock.done();
}
}
mod transmit {
use super::*;
#[test]
fn transmit_hex_uncnf_no_downlink() {
let expectations = [
Transaction::write_many(b"mac tx uncnf 42 23ff\r\n"),
Transaction::read_many(b"ok\r\nmac_tx_ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(
rn.transmit_hex(ConfirmationMode::Unconfirmed, 42, "23ff"),
Ok(None)
);
mock.done();
}
#[test]
fn transmit_hex_cnf_no_downlink() {
let expectations = [
Transaction::write_many(b"mac tx cnf 42 23ff\r\n"),
Transaction::read_many(b"ok\r\nmac_tx_ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(
rn.transmit_hex(ConfirmationMode::Confirmed, 42, "23ff"),
Ok(None)
);
mock.done();
}
#[test]
fn transmit_hex_uncnf_downlink() {
let expectations = [
Transaction::write_many(b"mac tx uncnf 42 23ff\r\n"),
Transaction::read_many(b"ok\r\nmac_rx 101 000102feff\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(
rn.transmit_hex(ConfirmationMode::Unconfirmed, 42, "23ff"),
Ok(Some(Downlink {
port: 101,
hexdata: "000102feff",
}))
);
mock.done();
}
#[test]
fn transmit_slice_uncnf_no_downlink() {
let expectations = [
Transaction::write_many(b"mac tx uncnf 42 23ff\r\n"),
Transaction::read_many(b"ok\r\nmac_tx_ok\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(
rn.transmit_slice(ConfirmationMode::Unconfirmed, 42, &[0x23, 0xff]),
Ok(None),
);
mock.done();
}
}
mod ensure_known_state {
use super::*;
use std::io::ErrorKind;
#[test]
fn already_clean() {
let expectations = [
Transaction::read_error(nb::Error::WouldBlock),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"invalid_param\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
rn.ensure_known_state().unwrap();
mock.done();
}
#[test]
fn non_empty_buffer() {
let expectations = [
Transaction::read_many(b"sys "),
Transaction::read_many(b"reset"),
Transaction::read_error(nb::Error::WouldBlock),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"invalid_param\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
rn.ensure_known_state().unwrap();
mock.done();
}
#[test]
fn retry() {
let expectations = [
Transaction::read_error(nb::Error::WouldBlock),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"ok\r\n"),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"wtf\r\n"),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"invalid_param\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
rn.ensure_known_state().unwrap();
mock.done();
}
#[test]
fn retry_failed() {
let expectations = [
Transaction::read_error(nb::Error::WouldBlock),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"uhm\r\n"),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"lol\r\n"),
Transaction::write_many(b"z\r\n"),
Transaction::read_many(b"wat\r\n"),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.ensure_known_state().unwrap_err(), Error::InvalidState);
mock.done();
}
#[test]
fn read_error() {
let expectations = [
Transaction::read_error(nb::Error::Other(MockError::Io(ErrorKind::BrokenPipe))),
];
let mut mock = SerialMock::new(&expectations);
let mut rn = rn2483_868(mock.clone());
assert_eq!(rn.ensure_known_state().unwrap_err(), Error::SerialRead);
mock.done();
}
}
}