use le_stream::{FromLeStream, ToLeStream};
use zb_core::endpoint::Reserved;
use zb_core::{Cluster, Endpoint, Profile};
use crate::frame::destination::{Destination, WeakDestination};
use crate::{Control, Extended, Fragmentation, FrameType};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ToLeStream)]
pub struct Header {
control: Control,
destination: WeakDestination,
cluster_id: u16,
profile_id: u16,
source_endpoint: u8,
counter: u8,
extended: Option<Extended>,
}
impl Header {
#[must_use]
pub fn new(
destination: Destination,
cluster_id: u16,
profile_id: u16,
source_endpoint: Endpoint,
counter: u8,
extended: Option<Extended>,
) -> Self {
let mut control = Control::empty();
control.set_frame_type(FrameType::Data);
control.set_destination(destination.into());
if extended.is_some() {
control.insert(Control::EXTENDED_HEADER);
}
Self {
control,
destination: destination.into(),
cluster_id,
profile_id,
source_endpoint: source_endpoint.into(),
counter,
extended,
}
}
#[must_use]
pub const fn control(&self) -> Control {
self.control
}
#[must_use]
pub const fn destination(&self) -> WeakDestination {
self.destination
}
#[must_use]
pub const fn cluster_id(&self) -> u16 {
self.cluster_id
}
pub fn cluster(&self) -> Result<Cluster, u16> {
self.cluster_id.try_into()
}
#[must_use]
pub const fn profile_id(&self) -> u16 {
self.profile_id
}
pub fn profile(&self) -> Result<Profile, u16> {
self.profile_id.try_into()
}
pub fn source_endpoint(&self) -> Result<Endpoint, Reserved> {
self.source_endpoint.try_into()
}
#[must_use]
pub const fn counter(&self) -> u8 {
self.counter
}
#[must_use]
pub const fn extended(&self) -> Option<Extended> {
self.extended
}
pub fn set_extended(&mut self, extended: Extended) -> Option<Extended> {
self.control.insert(Control::EXTENDED_HEADER);
self.extended.replace(extended)
}
pub fn drop_extended(&mut self) -> Option<Extended> {
self.control.remove(Control::EXTENDED_HEADER);
self.extended.take()
}
pub fn set_fragmentation(&mut self, fragmentation: Fragmentation) {
match fragmentation {
Fragmentation::None => {
self.drop_extended();
}
Fragmentation::First { blocks } => {
self.set_extended(Extended::first_fragment(blocks));
}
Fragmentation::Followup { index } => {
self.set_extended(Extended::followup_fragment(index));
}
}
}
}
impl FromLeStream for Header {
fn from_le_stream<T>(mut bytes: T) -> Option<Self>
where
T: Iterator<Item = u8>,
{
let control = Control::from_le_stream(&mut bytes)?;
let destination = control.deserialize_destination(&mut bytes)?;
let cluster_id = u16::from_le_stream(&mut bytes)?;
let profile_id = u16::from_le_stream(&mut bytes)?;
let source_endpoint = u8::from_le_stream(&mut bytes)?;
let counter = u8::from_le_stream(&mut bytes)?;
let extended = control.deserialize_extended_header(&mut bytes).ok()?;
Some(Self {
control,
destination,
cluster_id,
profile_id,
source_endpoint,
counter,
extended,
})
}
}