use core::fmt;
use core::fmt::Debug;
use core::mem;
use zigbee::internal::macros::impl_byte;
impl_byte! {
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct FrameControl(pub u8);
}
#[allow(missing_docs)]
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrameType {
GlobalCommand = 0b00,
ClusterCommand = 0b01,
Reserved = 0b10,
}
impl FrameControl {
pub fn frame_type(self) -> FrameType {
unsafe { mem::transmute((self.0 & mask::FRAME_TYPE) >> offset::FRAME_TYPE) }
}
pub fn is_manufacturer_specific(self) -> bool {
((self.0 & mask::MANUFACTURER_SPECIFIC) >> offset::MANUFACTURER_SPECIFIC) != 0
}
pub fn direction(self) -> bool {
(self.0 & mask::DIRECTION) != 0
}
pub fn disable_default_response(self) -> bool {
(self.0 & mask::DEFAULT_RESPONSE) != 0
}
}
mod mask {
pub(super) const FRAME_TYPE: u8 = 0b0000_0011; pub(super) const MANUFACTURER_SPECIFIC: u8 = 0b0000_0100; pub(super) const DIRECTION: u8 = 0b0000_1000; pub(super) const DEFAULT_RESPONSE: u8 = 0b0001_0000; }
mod offset {
pub(super) const FRAME_TYPE: u8 = 0;
pub(super) const MANUFACTURER_SPECIFIC: u8 = 2;
}
impl Debug for FrameControl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FrameControl")
.field("frame_type", &self.frame_type())
.field("manufacturer_specific", &self.is_manufacturer_specific())
.field("direction", &self.direction())
.field("disable_default_response", &self.disable_default_response())
.finish()
}
}
#[cfg(test)]
mod tests {
use byte::TryRead;
use super::*;
#[test]
fn unpack_frame_control() {
let input = [0x18];
let (frame_control, _) =
FrameControl::try_read(&input, ()).expect("Could not read FrameControl in test.");
assert_eq!(frame_control.frame_type(), FrameType::GlobalCommand);
assert!(!frame_control.is_manufacturer_specific());
assert!(frame_control.direction());
assert!(frame_control.disable_default_response());
}
#[test]
fn frame_control_with_local_command() {
let input = [0x19];
let (frame_control, _) =
FrameControl::try_read(&input, ()).expect("Could not read FrameControl in test.");
assert_eq!(frame_control.frame_type(), FrameType::ClusterCommand);
assert!(!frame_control.is_manufacturer_specific());
assert!(frame_control.direction());
assert!(frame_control.disable_default_response());
}
#[test]
fn frame_control_with_manufacturer_specific_flag() {
let input = [0x1d];
let (frame_control, _) =
FrameControl::try_read(&input, ()).expect("Could not read FrameControl in test.");
assert_eq!(frame_control.frame_type(), FrameType::ClusterCommand);
assert!(frame_control.is_manufacturer_specific());
assert!(frame_control.direction());
assert!(frame_control.disable_default_response());
}
#[test]
fn frame_control_with_direction_server_to_client() {
let input = [0x0d];
let (frame_control, _) =
FrameControl::try_read(&input, ()).expect("Could not read FrameControl in test.");
assert_eq!(frame_control.frame_type(), FrameType::ClusterCommand);
assert!(frame_control.is_manufacturer_specific());
assert!(frame_control.direction());
assert!(!frame_control.disable_default_response());
}
}