if_alloc! {
use crate::alloc::{string::String, fmt::format};
}
use bitfield_struct::bitfield;
use crate::conversion::Conversion;
pub trait IsDataUnit {}
#[bitfield(u64, order = Msb, conversion = false)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Data {
#[bits(8)]
byte_0_bits: u8,
#[bits(8)]
byte_1_bits: u8,
#[bits(8)]
byte_2_bits: u8,
#[bits(8)]
byte_3_bits: u8,
#[bits(8)]
byte_4_bits: u8,
#[bits(8)]
byte_5_bits: u8,
#[bits(8)]
byte_6_bits: u8,
#[bits(8)]
byte_7_bits: u8,
}
#[bitfield(u64, order = Msb, conversion = false)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Name {
#[bits(1)]
arbitrary_address_bits: bool,
#[bits(3)]
industry_group_bits: u8,
#[bits(4)]
vehicle_system_instance_bits: u8,
#[bits(7)]
vehicle_system_bits: u8,
#[bits(1)]
reserved_bits: bool,
#[bits(8)]
function_bits: u8,
#[bits(5)]
function_instance_bits: u8,
#[bits(3)]
ecu_instance_bits: u8,
#[bits(11)]
manufacturer_code_bits: u16,
#[bits(21)]
identity_number_bits: u32,
}
impl IsDataUnit for Data {}
impl IsDataUnit for Name {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pdu<U: IsDataUnit>(pub(crate) U);
impl Conversion<u64> for Pdu<Data> {
type Error = anyhow::Error;
fn from_bits(bits: u64) -> Self {
Self(Data(bits))
}
fn from_hex(hex_str: &str) -> Self {
let bits = u64::from_str_radix(hex_str, 16).unwrap_or_default();
Self(Data(bits))
}
fn try_from_bits(bits: u64) -> Result<Self, Self::Error> {
Ok(Self(Data(bits)))
}
fn try_from_hex(hex_str: &str) -> Result<Self, Self::Error> {
let bits = u64::from_str_radix(hex_str, 16).map_err(anyhow::Error::msg)?;
Ok(Self(Data(bits)))
}
fn into_bits(self) -> u64 {
self.0 .0
}
#[cfg(feature = "alloc")]
fn into_hex(self) -> String {
format(format_args!("{:016X}", self.0 .0))
}
}
impl Pdu<Data> {
#[must_use]
pub const fn byte_0(self) -> u8 {
self.0.byte_0_bits()
}
#[must_use]
pub const fn byte_1(self) -> u8 {
self.0.byte_1_bits()
}
#[must_use]
pub const fn byte_2(self) -> u8 {
self.0.byte_2_bits()
}
#[must_use]
pub const fn byte_3(self) -> u8 {
self.0.byte_3_bits()
}
#[must_use]
pub const fn byte_4(self) -> u8 {
self.0.byte_4_bits()
}
#[must_use]
pub const fn byte_5(self) -> u8 {
self.0.byte_5_bits()
}
#[must_use]
pub const fn byte_6(self) -> u8 {
self.0.byte_6_bits()
}
#[must_use]
pub const fn byte_7(self) -> u8 {
self.0.byte_7_bits()
}
#[must_use]
pub const fn to_le_bytes(&self) -> [u8; 8] {
self.0 .0.to_le_bytes()
}
#[must_use]
pub const fn to_be_bytes(&self) -> [u8; 8] {
self.0 .0.to_be_bytes()
}
#[must_use]
pub const fn to_ne_bytes(&self) -> [u8; 8] {
self.0 .0.to_ne_bytes()
}
#[must_use]
pub const fn to_le(&self) -> Self {
Self(Data(self.0 .0.to_le()))
}
#[must_use]
pub const fn to_be(&self) -> Self {
Self(Data(self.0 .0.to_be()))
}
}
impl Conversion<u64> for Pdu<Name> {
type Error = anyhow::Error;
fn from_bits(bits: u64) -> Self {
Self(Name(bits))
}
fn from_hex(hex_str: &str) -> Self {
let bits = u64::from_str_radix(hex_str, 16).unwrap_or_default();
Self(Name(bits))
}
fn try_from_bits(bits: u64) -> Result<Self, Self::Error> {
Ok(Self(Name(bits)))
}
fn try_from_hex(hex_str: &str) -> Result<Self, Self::Error> {
let bits = u64::from_str_radix(hex_str, 16).map_err(anyhow::Error::msg)?;
Ok(Self(Name(bits)))
}
fn into_bits(self) -> u64 {
self.0 .0
}
#[cfg(feature = "alloc")]
fn into_hex(self) -> String {
format(format_args!("{:016X}", self.0 .0))
}
}
impl Pdu<Name> {
#[must_use]
pub const fn arbitrary_address(&self) -> bool {
self.0.arbitrary_address_bits()
}
#[must_use]
pub const fn industry_group(&self) -> u8 {
self.0.industry_group_bits()
}
#[must_use]
pub const fn vehicle_system_instance(&self) -> u8 {
self.0.vehicle_system_instance_bits()
}
#[must_use]
pub const fn vehicle_system(&self) -> u8 {
self.0.vehicle_system_bits()
}
#[must_use]
pub const fn reserved(&self) -> bool {
self.0.reserved_bits()
}
#[must_use]
pub const fn function(&self) -> u8 {
self.0.function_bits()
}
#[must_use]
pub const fn function_instance(&self) -> u8 {
self.0.function_instance_bits()
}
#[must_use]
pub const fn ecu_instance(&self) -> u8 {
self.0.ecu_instance_bits()
}
#[must_use]
pub const fn manufacturer_code(&self) -> u16 {
self.0.manufacturer_code_bits()
}
#[must_use]
pub const fn identity_number(&self) -> u32 {
self.0.identity_number_bits()
}
}
#[cfg(test)]
mod data_tests {
use super::*;
#[test]
fn test_data_bitfield() -> Result<(), anyhow::Error> {
let data_a = Pdu::<Data>::from_hex("FFFF82DF1AFFFFFF");
let be_bytes_a: [u8; 8] = [0xFF, 0xFF, 0x82, 0xDF, 0x1A, 0xFF, 0xFF, 0xFF];
let le_bytes_a: [u8; 8] = [0xFF, 0xFF, 0xFF, 0x1A, 0xDF, 0x82, 0xFF, 0xFF];
assert_eq!(be_bytes_a, data_a.to_be_bytes());
assert_eq!(le_bytes_a, data_a.to_le_bytes());
assert_eq!(18446606493475143679, data_a.into_bits());
assert_eq!(Pdu::<Data>(Data(18446743089616977919)), data_a.to_be());
assert_eq!(Pdu::<Data>(Data(18446606493475143679)), data_a.to_le());
Ok(())
}
#[test]
fn test_name_bitfield() {
let name_a = Name::new()
.with_arbitrary_address_bits(true)
.with_industry_group_bits(0)
.with_vehicle_system_instance_bits(0x5)
.with_vehicle_system_bits(0x6)
.with_reserved_bits(false)
.with_function_bits(0x5)
.with_function_instance_bits(0x2)
.with_ecu_instance_bits(0x1)
.with_manufacturer_code_bits(0x122)
.with_identity_number_bits(0xB0309);
let pdu_name = Pdu::<Name>(name_a);
let bytes_a: [u8; 8] = [0x09, 0x03, 0x4B, 0x24, 0x11, 0x05, 0x0C, 0x85];
let name_a_bytes = pdu_name.into_bits().to_le_bytes();
assert_eq!(bytes_a, name_a_bytes);
}
}