dlms_cosem 0.2.0

A `no_std` library for parsing DLMS/COSEM messages.
Documentation
use nom::{
  IResult,
  number::streaming::{u8, be_u32},
  multi::length_value,
};

use crate::{DateTime, Data};

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LongInvokeIdAndPriority(pub(crate) u32);

impl LongInvokeIdAndPriority {
  pub fn parse(input: &[u8]) -> IResult<&[u8], Self> {
    let (input, id) = be_u32(input)?;
    Ok((input, Self(id)))
  }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Priority {
  Normal,
  High,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ServiceClass {
  Confirmed,
  Unconfirmed,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ProcessingOption {
  ContinueOnError,
  BreakOnError,
}

impl LongInvokeIdAndPriority {
  pub fn priority(&self) -> Priority {
    if (self.0 & (1 << 31)) == 0 {
      Priority::Normal
    } else {
      Priority::High
    }
  }

  pub fn processing_option(&self) -> ProcessingOption {
    if (self.0 & (1 << 29)) == 0 {
      ProcessingOption::ContinueOnError
    } else {
      ProcessingOption::BreakOnError
    }
  }

  pub fn self_descriptive(&self) -> bool {
    (self.0 & (1 << 28)) != 0
  }

  pub fn service_class(&self) -> ServiceClass {
    if (self.0 & (1 << 30)) == 0 {
      ServiceClass::Unconfirmed
    } else {
      ServiceClass::Confirmed
    }
  }

  pub fn invoke_id(&self) -> u32 {
    self.0 & 0x00ffffff
  }
}

#[derive(Debug, Clone, PartialEq)]
pub struct DataNotification {
  pub(crate) long_invoke_id_and_priority: LongInvokeIdAndPriority,
  pub(crate) date_time: DateTime,
  pub(crate) notification_body: Data,
}

impl DataNotification {
  pub fn priority(&self) -> Priority {
    self.long_invoke_id_and_priority.priority()
  }

  pub fn self_descriptive(&self) -> bool {
    self.long_invoke_id_and_priority.self_descriptive()
  }

  pub fn processing_option(&self) -> ProcessingOption {
    self.long_invoke_id_and_priority.processing_option()
  }

  pub fn service_class(&self) -> ServiceClass {
    self.long_invoke_id_and_priority.service_class()
  }

  pub fn invoke_id(&self) -> u32 {
    self.long_invoke_id_and_priority.invoke_id()
  }

  pub fn parse(input: &[u8]) -> IResult<&[u8], Self> {
    let (input, long_invoke_id_and_priority) = LongInvokeIdAndPriority::parse(input)?;
    let (input, date_time) = length_value(u8, DateTime::parse)(input)?;
    let (input, notification_body) = Data::parse(input)?;
    Ok((input, Self { long_invoke_id_and_priority, date_time, notification_body }))
  }
}