use core::fmt::{self, Display};
use core::str::FromStr;
use bitflags::{bitflags, parser};
use le_stream::{FromLeStream, ToLeStream};
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, ToLeStream)]
#[repr(transparent)]
pub struct TxOptions(u8);
bitflags! {
impl TxOptions: u8 {
const SECURITY_ENABLED = 0x01;
const USE_NWK_KEY = 0x02;
const ACKNOWLEDGED_TRANSMISSION = 0x04;
const FRAGMENTATION_PERMITTED = 0x08;
const INCLUDE_EXTENDED_NONCE = 0x10;
}
}
impl Display for TxOptions {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
parser::to_writer(self, formatter)
}
}
impl FromStr for TxOptions {
type Err = parser::ParseError;
fn from_str(flags: &str) -> Result<Self, Self::Err> {
parser::from_str(flags)
}
}
impl FromLeStream for TxOptions {
fn from_le_stream<T>(bytes: T) -> Option<Self>
where
T: Iterator<Item = u8>,
{
u8::from_le_stream(bytes).and_then(Self::from_bits)
}
}
#[cfg(test)]
mod tests {
use le_stream::{FromLeStream, ToLeStream};
use super::TxOptions;
const RESERVED_OPTION: u8 = 0x20;
#[test]
fn uses_apsde_data_request_bit_assignments() {
assert_eq!(TxOptions::SECURITY_ENABLED.bits(), 0x01);
assert_eq!(TxOptions::USE_NWK_KEY.bits(), 0x02);
assert_eq!(TxOptions::ACKNOWLEDGED_TRANSMISSION.bits(), 0x04);
assert_eq!(TxOptions::FRAGMENTATION_PERMITTED.bits(), 0x08);
assert_eq!(TxOptions::INCLUDE_EXTENDED_NONCE.bits(), 0x10);
}
#[test]
fn combined_options_round_trip() {
let options = TxOptions::SECURITY_ENABLED
| TxOptions::ACKNOWLEDGED_TRANSMISSION
| TxOptions::FRAGMENTATION_PERMITTED;
let bytes: Vec<_> = options.to_le_stream().collect();
assert_eq!(bytes, [0x0d]);
assert_eq!(TxOptions::from_le_stream(bytes.into_iter()), Some(options));
}
#[test]
fn rejects_reserved_bits() {
assert_eq!(
TxOptions::from_le_stream([RESERVED_OPTION].into_iter()),
None
);
}
}